我不久前制作了这个脚本,因为我在使用互联网上找到的安装程序和修复程序时遇到了问题。它将我在互联网上找到的所有技巧和技巧整合到一个 powershell 脚本中。
要运行脚本,您需要执行以下操作:
上面的每一个都应该放在自己的文件夹中。如果您将脚本保存(然后点源)在包含这三个文件夹的文件夹中,它将自动为您检测所有内容。您还可以将您在 powershell 中的当前位置设置为该文件夹并将脚本直接复制到您的会话中,它也会检测到所有内容。
一旦脚本被点源或粘贴到提升的 Powershell 实例中,您可以通过调用 Install-VB6 来运行它。
如果您想覆盖任何默认行为,它还具有以下参数:
| Parameter |
Type |
Usage |
Vb6InstallerPath |
String |
Path of main VB6 Installer folder |
SP6InstallerPath |
String |
Path of Service Pack 6 Installer folder |
SkipMouseWheel |
Switch |
Skip installing the Mouse Wheel Fixer folder |
MouseWheelPath |
String |
Path of Mouse Wheel fixer. Ignored if -SkipMouseWheel is specified |
Regsvr32Path |
String |
Path to regsvr32.exe. Uses '%SYSTEMROOT%\SysWoW64\regsvr32.exe' if not specified |
RegEditPath |
String |
Path to regedit.exe. '%SYSTEMROOT%\regedit.exe' if not specified |
OrganizationName |
String |
Sets the organization name in the VB6 installer |
注意事项:
- VB6 和 SP6 安装程序不喜欢从网络驱动器运行,因此如果检测到安装文件夹之一不在本地驱动器上,脚本将停止。
- 我只用 VB6 Pro 测试过这个,而不是 VB6 Enterprise。
- 它不安装 MSDN。
安装-VB6.ps1
#Requires -RunAsAdministrator
#Requires -Version 3
<#
.SYNOPSIS
Installs VB6 to the computer.
.DESCRIPTION
Installs VB6 ide with Service Pack 6 and (optional) Mouse Wheel Fix to the local computer.
.PARAMETER Vb6InstallerPath
The path to the VB6 installer folder.
.PARAMETER SP6InstallerPath
The path the the Service Pack 6 installer folder.
.PARAMETER SkipMouseWheel
Skip installing the Mouse Wheel fix.
.PARAMETER MouseWheelPath
The path the Mouse wheel fix folder.
.PARAMETER Regsvr32Path
The path to RegSvr32.exe
.PARAMETER OrganizationName
The organization name
.PARAMETER RegEditPath
The path to regedit.exe
#>
Function Install-VB6{
[CmdletBinding()]
param (
[Parameter(Mandatory=$false)]
[string]$Vb6InstallerPath,
[Parameter(Mandatory=$false)]
[string]$SP6InstallerPath,
[Parameter(Mandatory=$false)]
[switch]$SkipMouseWheel,
[Parameter(Mandatory=$false)]
[string]$MouseWheelPath,
[Parameter(Mandatory=$false)]
[string]$Regsvr32Path,
[Parameter(Mandatory=$false)]
[string]$OrganizationName,
[Parameter(Mandatory=$false)]
[string]$RegEditPath
)
# Tests if the path is a local path. The installer doesn't like network paths.
function Test-LocalDrive{
[CmdletBinding()]
[OutputType([bool])]
param(
[Parameter(Mandatory=$true,
Position=0)]
[string]$Path
)
begin{
$localDrives = Get-WmiObject -Class Win32_logicaldisk -Filter "DriveType<>4" -Property "DeviceID" | Foreach-Object {$_.DeviceID.Replace(":", "")}
}
process{
if(!([bool](Test-Path -Path $Path))){
return $false
}
$item = Get-Item -Path $Path
$drive = $item.PSDrive
if($null -eq $drive){
return $false
}
return ($localDrives -contains $drive.Name)
}
}
function Search-ForFile{
[CmdletBinding()]
[OutputType([System.IO.FileInfo])]
param(
[Parameter(Mandatory=$true,
Position=0)]
[string]$File,
[Parameter(Mandatory=$true,
Position=1)]
[string]$CurrentLocation,
[switch]$IncludeSubDirectory
)
process{
$newPath = $currentLocation
if($IncludeSubDirectory.IsPresent){
$newPath = Join-Path -Path $newPath -ChildPath "*"
}
$newPath = Join-Path -Path $newPath -ChildPath $file
$item = @(Get-Item -Path $newPath)
if($null -eq $item -or $item.Count -eq 0 -or $null -eq $item[0]){
throw ("Could Not find the {0} file." -f $file)
}
return $item[0]
}
}
#region Setting Up File Paths
$currentLocation = $PSScriptRoot
if([System.String]::IsNullOrWhiteSpace($currentLocation)){
$currentLocation = (Get-Location)
}
if([System.String]::IsNullOrWhiteSpace($currentLocation)){
throw "Unable to determine current location"
}
if(!$PSBoundParameters.ContainsKey("Vb6InstallerPath") -or [System.String]::IsNullOrWhiteSpace($Vb6InstallerPath)){
if(!(Test-LocalDrive -Path ($currentLocation))){
Write-Error "The script cannot be ran from a network share."
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
$installerInfo = Search-ForFile -File "SETUP.EXE" -CurrentLocation $currentLocation -IncludeSubDirectory
$installFolder = $installerInfo.DirectoryName
}
else {
if(!(Test-LocalDrive -Path ($Vb6InstallerPath))){
Write-Error "The VB6 Installer Path cannot be a share."
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
$installFolder = $Vb6InstallerPath
$installerInfo = Search-ForFile -File "SETUP.EXE" -CurrentLocation $installFolder
}
$installer2Info = Search-ForFile -File "ACMSETUP.EXE" -CurrentLocation $installFolder -IncludeSubDirectory
$installLocation = $installerInfo.FullName
$install2Location = $installer2Info.FullName
if(!$PSBoundParameters.ContainsKey("SP6InstallerPath") -or [System.String]::IsNullOrWhiteSpace($SP6InstallerPath)){
if(!(Test-LocalDrive -Path ($currentLocation))){
Write-Error "The script cannot be ran from a network share."
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
$SP6Info = Search-ForFile -File "setupsp6.exe" -CurrentLocation $currentLocation -IncludeSubDirectory
$SP6Folder = $SP6Info.DirectoryName
}
else {
if(!(Test-LocalDrive -Path ($SP6InstallerPath))){
Write-Error "The SP6 Installer Path cannot be a network share."
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
$SP6Folder = $SP6InstallerPath
$SP6Info = Search-ForFile -File "setupsp6.exe" -CurrentLocation $SP6Folder
}
$SP6Location = $SP6Info.FullName
if(!$SkipMouseWheel.IsPresent){
if(!$PSBoundParameters.ContainsKey("MouseWheelPath") -or [System.String]::IsNullOrWhiteSpace($MouseWheelPath)){
if(!(Test-LocalDrive -Path ($currentLocation))){
Write-Error "The script cannot be ran from a network share."
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
$MouseWheelDllInfo = Search-ForFile -File "VB6IDEMouseWheelAddin.dll" -CurrentLocation $currentLocation -IncludeSubDirectory
$MouseWheelRegistryInfo = Search-ForFile -File "VBA Mouse Wheel Fix.reg" -CurrentLocation $currentLocation -IncludeSubDirectory
}
else {
if(!(Test-LocalDrive -Path ($SP6InstallerPath))){
Write-Error "The Mouse Wheel Path cannot be a network share."
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
$MouseWheelDllInfo = Search-ForFile -File "VB6IDEMouseWheelAddin.dll" -CurrentLocation $MouseWheelPath
$MouseWheelRegistryInfo = Search-ForFile -File "VBA Mouse Wheel Fix.reg" -CurrentLocation $MouseWheelPath
}
$MouseWheelDll = $MouseWheelDllInfo.FullName
$MouseWheelRegistry = $MouseWheelRegistryInfo.FullName
}
if(!$PSBoundParameters.ContainsKey("Regsvr32Path") -or [System.String]::IsNullOrWhiteSpace($Regsvr32Path)){
$regSvrPath = "$($env:systemroot)\SysWoW64\regsvr32.exe"
}
else{
$regSvrPath = $Regsvr32Path
}
if(!$PSBoundParameters.ContainsKey("RegEditPath") -or [System.String]::IsNullOrWhiteSpace($RegEditPath)){
$RegEditPath = "$($env:systemroot)\regedit.exe"
}
#endregion Setting Up File Paths
#region Test Required Installer Paths Exist
if(!([bool](Test-Path -Path $regSvrPath))){
Write-Error ("Unable to find '{0}'.`r`nThe exe must exist." -f $regSvrPath)
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
if(!([bool](Test-Path -Path $RegEditPath))){
Write-Error ("Unable to find '{0}'.`r`nThe exe must exist." -f $RegEditPath)
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
if(!$SkipMouseWheel.IsPresent){
if(!([bool](Test-Path -Path $MouseWheelDll))){
Write-Error ("Unable to find '{0}'.`r`nThe 'MouseWheel' Folder must be in the same directory as the install script and the file must exist." -f $MouseWheelDll)
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
if(!([bool](Test-Path -Path $MouseWheelRegistry))){
Write-Error ("Unable to find '{0}'.`r`nThe 'MouseWheel' Folder must be in the same directory as the install script and the file must exist." -f $MouseWheelRegistry)
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
}
if(!([bool](Test-Path -Path $installFolder))){
Write-Error ("Unable to find '{0}'.`r`nThe 'Installer' Folder must be in the same directory as the install script." -f $installFolder)
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
if(!([bool](Test-Path -Path $installLocation))){
Write-Error ("Unable to find '{0}'.`r`nThe 'Installer' Folder must be in the same directory as the install script and the file must exist." -f $installLocation)
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
if(!([bool](Test-Path -Path $install2Location))){
Write-Error ("Unable to find '{0}'.`r`nThe 'Installer' Folder must be in the same directory as the install script and the file must exist." -f $install2Location)
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
if(!([bool](Test-Path -Path $SP6Location))){
Write-Error ("Unable to find '{0}'.`r`nThe 'SP6' Folder must be in the same directory as the install script and the file must exist." -f $SP6Location)
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
return
}
#endregion Test Required Installer Paths Exist
#region Installer Compatibility
# The installer doesn't auto-elevate to run as an administrator.
# We are setting the required keys in the registry to force the installers to run as administrator
# Same as running the 'troubleshoot compatibilty' wizard and selecting the exe's to run as admins.
Write-Host "Setting compatibility mode on setup files."
$layersPath = "REGISTRY::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
if(){
New-Item -Path $layersPath -Force | Out-Null
}
$registryPath = Get-Item -LiteralPath $layersPath
if($null -eq $registryPath.GetValue($installLocation, $null)){
New-ItemProperty -Path $layersPath -Name $installLocation -Value "^ WINXPSP3" -PropertyType "String" -Force | Out-Null
}
if($null -eq $registryPath.GetValue($SP6Location, $null)){
New-ItemProperty -Path $layersPath -Name $SP6Location -Value "^ WINXPSP3" -PropertyType "String" -Force | Out-Null
}
#endregion Installer Compatibility
#region Previous Install Cleanup
# Locations and keys where old vb6 installs can live.
Write-Host "Cleaning up previous install."
$itemsToDelete = @(
"C:\Program Files*\Microsoft Visual Studio\Common",
"C:\Program Files*\Microsoft Visual Studio\MSDN",
"C:\Program Files*\Microsoft Visual Studio\MSDN98",
"C:\Program Files*\Microsoft Visual Studio\VB98",
"C:\Program Files*\Microsoft Visual Studio\VC98",
"C:\Program Files*\Microsoft Visual Studio\*.HTM",
"C:\Program Files*\Microsoft Visual Studio\*.TXT",
"C:\Program Files*\Common Files\Microsoft Shared\MSDesigners98",
"C:\Program Files*\Common Files\Microsoft Shared\MSDN",
"C:\Program Files*\Common Files\Microsoft Shared\VS98",
"C:\Program Files*\Common Files\Microsoft Shared\Wizards98",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\DevStudio",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\HTML Help Collections",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\MSVSDG",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\Visual Basic\6.0",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\Visual Component Manager",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\Visual Modeler",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\DevStudio",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\HTML Help Collections",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\MSVSDG",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Visual Basic\6.0",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Visual Component Manager",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Visual Modeler",
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\6.0",
"REGISTRY::HKEY_CURRENT_USER\Software\Microsoft\DevStudio",
"REGISTRY::HKEY_CURRENT_USER\Software\Microsoft\MSVSDG",
"REGISTRY::HKEY_CURRENT_USER\Software\Microsoft\Visual Basic\6.0",
"REGISTRY::HKEY_CURRENT_USER\Software\Microsoft\Visual Modeler",
"REGISTRY::HKEY_CURRENT_USER\Software\Microsoft\VisualFoxPro",
"REGISTRY::HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\6.0"
)
$itemsToDelete | Where-Object { Test-Path -Path $_ } | Remove-Item -Force -Recurse | Out-Null
#endregion Previous Install Cleanup
#region Installer Registry Permissions
# The installer needs to be able to write to 'HKEY_CLASSES_ROOT\RDSServer.DataFactory\Clsid'
# but since the installer isn't built for windows and we have to force it to run as an administrator
# we have to give explicit permissions for your computers Administrators group to write to this key (and all its children)
Write-Host "Setting required permissions for installing user on registry."
$registryPermissionPath = "REGISTRY::HKEY_CLASSES_ROOT\RDSServer.DataFactory\Clsid"
Write-Host "`tSetting Up required information."
$acl = Get-ACL -Path $registryPermissionPath
$oldOwner = [System.Security.Principal.NTAccount]::new($acl.Owner)
$administratorIdentity = [System.Security.Principal.NTAccount]::new("Administrators")
Write-Host "`tGiving the script required permissions."
$import = '[DllImport("ntdll.dll")] public static extern int RtlAdjustPrivilege(ulong a, bool b, bool c, ref bool d);'
$ntdll = Add-Type -Member $import -Name NtDll -PassThru
$privileges = @{ SeTakeOwnership = 9; SeBackup = 17; SeRestore = 18 }
foreach ($i in $privileges.Values) {
$null = $ntdll::RtlAdjustPrivilege($i, 1, 0, [ref]0)
}
Write-Host "`tGettting The registry key."
$regKey = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey("RDSServer.DataFactory\Clsid", 'ReadWriteSubTree', 'TakeOwnership')
# We force the Administrators group to be the owner on the key so we can then add required the permissions.
Write-Host "`tSetting Owner."
$acl.SetOwner($administratorIdentity)
$regKey.SetAccessControl($acl)
Write-Host "`tSetting Permission."
$permission = [System.Security.AccessControl.RegistryAccessRule]::new($administratorIdentity, "FullControl", "ContainerInherit", "InheritOnly", "Allow")
$acl.AddAccessRule($permission)
$permission2 = [System.Security.AccessControl.RegistryAccessRule]::new($administratorIdentity, "FullControl", "Allow")
$acl.AddAccessRule($permission2)
$regKey.SetAccessControl($acl)
# Reset the owner to clean-up
Write-Host "`tResetting Owner."
$acl.SetOwner($oldOwner)
$regKey.SetAccessControl($acl)
#endregion Installer Registry Permissions
#region Install
Write-Host "`tStarting Install."
$tempPath = [System.IO.Path]::GetTempPath()
$tempFolder = Join-Path -Path $tempPath -ChildPath ([System.Guid]::NewGuid().ToString("n"))
New-Item -Path $tempFolder -ItemType Directory -Force | Out-Null
$KeyFile = Join-Path -Path $tempFolder -ChildPath ("{0}.dat" -f [System.Guid]::NewGuid().ToString("n"))
$keyFileText = @"
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Basic\SetupWizard]
"aspo"=dword:00000000
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Basic\SetupWizard]
"aspo"=dword:00000000
"@
$keyFileText | Set-Content -Path $keyFile -Force
& $RegEditPath /S $KeyFile
[string[]]$installerArguments = ("/T", "VB98PRO.stf", "/S", $installFolder, "/n", ($env:USERNAME), "/k", "0000000000", "/b", "1", "/qn1")
if($PSBoundParameters.ContainsKey("OrganizationName") -and ![System.String]::IsNullOrWhiteSpace($OrganizationName)){
$installerArguments += "/o"
$installerArguments += $OrganizationName
}
Start-Process -FilePath $install2Location -wait -NoNewWindow -ArgumentList $installerArguments
Start-Process -FilePath $SP6Location -wait -NoNewWindow -ArgumentList ("/qn1")
Write-Host "Setting Vb6 Compatibility"
$vb6ExeLocations = @(Get-Item -Path "C:\Program Files*\Microsoft Visual Studio\VB98\VB6.EXE" | Select-Object -ExpandProperty FullName)
$registryPath = Get-Item -LiteralPath $layersPath
foreach($vb6ExeLocation in $vb6ExeLocations){
if($null -eq $registryPath.GetValue($vb6ExeLocation, $null)){
New-ItemProperty -Path $layersPath -Name $vb6ExeLocation -Value "^ WINXPSP3" -PropertyType "String" -Force | Out-Null
}
}
if(!$SkipMouseWheel.IsPresent){
Write-Host "Installing Mouse Wheel"
& $regSvrPath /s $MouseWheelDll
& $RegEditPath /S $MouseWheelRegistry
$registryHeaderText = @"
Windows Registry Editor Version 5.00
"@
$registryItemFormat = @"
[{0}\SOFTWARE\Microsoft\Visual Basic\6.0\Addins\VB6IDEMouseWheelAddin.Connect]
"FriendlyName"="MouseWheel Fix"
"LoadBehavior"=dword:00000003
"CommandLineSafe"=dword:00000000
"@
$users = Get-ChildItem -Path "REGISTRY::HKEY_USERS" | Where-Object {$_.Name -notlike "*_Classes"} | Select-Object -ExpandProperty Name
$content = $registryHeaderText
# Install for every user.
foreach($user in $users){
$content += ($registryItemFormat -f $user)
}
$MouseWheelApplyRegistry = Join-Path -Path $tempFolder -ChildPath ("{0}.reg" -f [System.Guid]::NewGuid().ToString("n"))
$content | Set-Content -Path $MouseWheelApplyRegistry -Force
Start-Process $RegEditPath -wait -NoNewWindow -ArgumentList ("/S", $MouseWheelApplyRegistry)
Write-Host "You will still need to enable Mouse Wheel fix in the VB6 IDE." -BackgroundColor Black -ForegroundColor Red
Write-Host "Open a Visual Basic project and go to 'Add-Ins' -> 'Add-In Manager...' " -BackgroundColor Black -ForegroundColor Red
Write-Host "Select 'MouseWheel Fix' and click 'Loaded/Unloaded' and 'Load on Startup'" -BackgroundColor Black -ForegroundColor Red
}
Remove-Item -Path $tempFolder -Force -Recurse | Out-Null
#endregion Install
Write-Host "Install Complete"
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
}