当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 重新审视 PowerShell 版本清单

作者:精品下载站 日期:2024-12-14 08:03:35 浏览:17 分类:玩电脑

重新审视 PowerShell 版本清单


[玩转系统] 重新审视 PowerShell 版本清单

过去,我分享了各种 PowerShell 方法,您可以使用它们来清点安装的 PowerShell 版本。但我认为我现在有了最好的方法,无需在硬盘驱动器中搜索 powershell.exe 和 pwsh.exe,我认为这仍然是一种可能性,也是我应该写的东西。

相反,我依赖这样一个事实:如果安装了 PowerShell 或某些版本的 PowerShell 7,则应该使用 Get-Command 找到可执行文件。顺便说一句,我想出的代码是为了在 Windows 平台上运行而设计的。在非 Windows 系统上,PowerShell 7 或预览版是您可以安装的唯一版本,并且这些操作系统已经具有用于检查已安装软件包的适当工具。

使用 Get 命令

在 Windows 中,我可以从 Get-Command 开始。

$cmd = Get-Command -name powershell.exe -commandtype Application

如果找到该文件,我可以运行它并从主机中提取版本信息。这将是对 Get-Command 提供的版本信息的补充。

&$cmd.path -nologo -noprofile -command { Get-Host}

有了这些信息,我可以创建一个自定义对象。

[pscustomobject]@{
    PSTypeName      = "PSInstallInfo"
    Name            = $cmd.Name
    FileVersion     = $cmd.Version
    PSVersion       = $psh.Version
    Comments        = $null
    Computername    = [System.Environment]::MachineName
    OperatingSystem = $os
}

我添加了计算机名称,这在以后查询一堆远程计算机时会很有帮助。我本可以使用 $env:Computername 因为我预计这只会在 Windows 平台上使用,但它可能不会。在这种情况下,我需要使用 .NET Framework,因为 $env:Computername 在非 Windows 平台上不可用。我还使用 Get-CimInstance 获取操作系统。

$os = (Get-CimInstance -ClassName Win32_OperatingSystem -Property Caption).caption

您还会看到我正在创建一个定义类型名称为“PSInstalledInfo”的自定义对象。

库存脚本

当然,您想查看代码。

#requires -version 5.1

#Use Get-Command to test for installed versions of PowerShell

[cmdletbinding()]
Param()

Write-Verbose "Searching for PowerShell installations on $([System.Environment]::MachineName)"

#build a list to hold the results
$list = [System.Collections.Generic.list[object]]::New()

#get the operating system
$os = (Get-CimInstance -ClassName Win32_OperatingSystem -Property Caption).caption

#Windows Powershell
Try {
    Write-Verbose "Testing for Windows PowerShell"
    $cmd = Get-Command -Name powershell.exe -ErrorAction stop
    if ($cmd) {
        Write-Verbose "Using $($cmd.path)"
        $psh = &$cmd.path -nologo -noprofile -command { Get-Host }

        $result = [pscustomobject]@{
            PSTypeName      = "PSInstallInfo"
            Name            = $cmd.Name
            FileVersion     = $cmd.Version
            PSVersion       = $psh.Version
            Comments        = $null
            Computername    = [System.Environment]::MachineName
            OperatingSystem = $os
        }
        Remove-Variable cmd
        $list.Add($result)
    }
}
Catch {
    Write-Verbose "Windows PowerShell not installed on $([Environment]::MachineName)."
}

#test for PowerShell 2.0 engine or feature

Write-Verbose "Testing for Windows PowerShell 2.0 engine or feature"

Try {
    #get computersystem roles to determine if running on a server or client
    $cs = Get-CimInstance -ClassName win32_Computersystem -Property Roles -ErrorAction Stop
    $rolestring = $cs.roles -join ","
    Write-Verbose "Detected roles $rolestring"
    if ($rolestring -match 'Server_NT|Domain_Controller') {
        Write-Verbose "Running Get-WindowsFeature"
        $f = Get-WindowsFeature PowerShell-V2
    }
    else {
        Write-Verbose "Running Get-WindowsOptionalFeature"
        $f = Get-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root
    }

    if ($f.installed -OR $f.State -eq 'Enabled') {
        $result = [pscustomobject]@{
            PSTypeName      = "PSInstallInfo"
            Name            = "powershell.exe"
            FileVersion     = $null
            PSVersion       = "2.0"
            Comments        = "Windows PowerShell 2.0 feature enabled or installed"
            Computername    = [System.Environment]::MachineName
            OperatingSystem = $os
        }
        $list.Add($result)
    }
}
Catch {
    Write-Verbose "Windows PowerShell 2.0 not installed on $([Environment]::MachineName)."
}
#PowerShell 7

Write-Verbose "Testing for PowerShell 7"

Try {
    $cmd = Get-Command -Name "pwsh.exe" -CommandType Application -ErrorAction Stop

    if ($cmd) {
        foreach ($item in $cmd) {
            Write-Verbose "Using $($item.path)"
            $psh = &$item.path -nologo -noprofile -command { Get-Host }
            $PSVer = $psh.version

            #test fpr SSH
            Write-Verbose "Testing for SSH on $([Environment]::MachineName)"
            $ProgressPreference = "SilentlyContinue"
            $ssh = Test-NetConnection -ComputerName ([Environment]::MachineName) -Port 22 -WarningAction SilentlyContinue -InformationLevel Quiet
            If ($ssh) {
                $note = "SSH detected"
            }
            else {
                $note = ""
            }

            $result = [pscustomobject]@{
                PSTypeName      = "PSInstallInfo"
                Name            = $item.Name
                FileVersion     = $item.Version
                PSVersion       = $PSVer
                Comments        = $note.Trim()
                Computername    = [System.Environment]::MachineName
                OperatingSystem = $os
            }

            $list.Add($result)
        } #foreach item
        Remove-Variable cmd
    }
}
Catch {
    Write-Verbose "PowerShell 7 not installed on $([Environment]::MachineName)."
}

Write-Verbose "Testing for PowerShell 7 preview"
#filter out preview if running this command IN a preview
if ($host.version.PSSemVerPreReleaseLabel) {
    Write-Verbose "PowerShell preview detected"
    $n = "pwsh.exe"
}
else {
    $n = "pwsh-preview.cmd"
}
Try {
    $cmd = Get-Command -Name $n -CommandType Application -ErrorAction Stop

    if ($cmd) {
        foreach ($item in $cmd) {
            Write-Verbose "Using $($item.path)"
            $psh = &$item.path -nologo -noprofile -command { Get-Host }
            $PSVer = $psh.version
            if ($psver.PSSemVerPreReleaseLabel) {
                [string]$note = $psver.PSSemVerPreReleaseLabel
            }
            else {
                [string]$note = ""
            }

            #test fpr SSH
            Write-Verbose "Testing for SSH on $([Environment]::MachineName)."
            $ProgressPreference = "SilentlyContinue"
            $ssh = Test-NetConnection -ComputerName ([Environment]::MachineName) -Port 22 -WarningAction SilentlyContinue -InformationLevel Quiet
            if ($ssh) {
                $note += " SSH detected"
            }
            $result = [pscustomobject]@{
                PSTypeName      = "PSInstallInfo"
                Name            = $item.Name
                FileVersion     = $item.Version
                PSVersion       = $PSVer
                Comments        = $note.Trim()
                Computername    = [System.Environment]::MachineName
                OperatingSystem = $os
            }

            if ($list.Psversion -notcontains $result.PSVersion) {
                $list.Add($result)
            }
            else {
                Write-Verbose "Skipping duplicate version $($result.version)"
            }
        } #foreach item
    }
}
Catch {
    Write-Verbose "PowerShell 7 preview not installed on $([Environment]::MachineName)."
}

#write the results to the pipeline
$list | Sort-Object -Property PSVersion

当你查看代码时,我正在搜索 PowerShell 和 pwsh 版本。我还在测试运行 PowerShell 7 的系统上是否启用了 ssh。我不想依赖于检查 sshd 服务,因为我不想做出假设。虽然我假设端口为 22。您还会看到我为 Test-NetConnection 指定了计算机名。在我的测试中,如果我不指定计算机名,PowerShell 会尝试连接到公共 IP 地址。

这是它在我的本地计算机上的外观。

[玩转系统] 重新审视 PowerShell 版本清单

因为这是一个脚本,所以我可以将它与 Invoke-Command 一起使用来查询远程 Windows 计算机,当然前提是启用了 PowerShell 远程处理。

[玩转系统] 重新审视 PowerShell 版本清单

使用类型做更多事情

当然,由于我有一个自定义对象,所以我可以做更多的事情。例如定义默认属性的设置。

Update-TypeData -TypeName PSInstallInfo -DefaultDisplayPropertySet "Name","FileVersion","PSVersion","Comments","ComputerName" -force

[玩转系统] 重新审视 PowerShell 版本清单

这消除了使用 Invoke-Command 时获得的讨厌的 RunspaceID 属性。

或者,我真的可以开始定义一个自定义格式文件,这是我使用值得信赖的 New-PSFormatXML 命令完成的。

<!--
Format type data generated 07/13/2021 12:14:45 by PROSPERO\Jeff

This file was created using the New-PSFormatXML command that is part
of the PSScriptTools module.

https://github.com/jdhitsolutions/PSScriptTools
-->
<Configuration>
  <ViewDefinitions>
    <View>
      <!--Created 07/13/2021 12:14:45 by PROSPERO\Jeff-->
      <Name>default</Name>
      <ViewSelectedBy>
        <TypeName>PSInstallInfo</TypeName>
      </ViewSelectedBy>
      <GroupBy>
        <ScriptBlock>"{0} [{1}]" -f $_.Computername,$_.OperatingSystem</ScriptBlock>
        <Label>Computername</Label>
      </GroupBy>
      <TableControl>
        <!--Delete the AutoSize node if you want to use the defined widths
        <AutoSize />.-->
        <TableHeaders>
          <TableColumnHeader>
            <Label>Name</Label>
            <Width>19</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>FileVersion</Label>
            <Width>15</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>PSVersion</Label>
            <Width>15</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Comments</Label>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <TableColumnItems>
              <TableColumnItem>
                <PropertyName>Name</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>FileVersion</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <ScriptBlock>
                if (($host.name -match "console|code|serverremotehost") -AND ($_.name -match "preview")) {
                  "$([char]27)[38;5;219m$($_.PSVersion)$([char]27)[0m"
                }
                else {
                  $_.PSVersion
                }
                </ScriptBlock>
              </TableColumnItem>
              <TableColumnItem>
               <ScriptBlock>
                if (($host.name -match "console|code|serverremotehost") -AND ($_.comments-match "SSH detected")) {
                  <!-- replace SSH Detected with an ANSI sequence-->
                  $_.comments -replace "SSH detected","$([char]27)[1;38;5;155mSSH detected$([char]27)[0m"
                }
                else {
                  $_.comments
                }
                </ScriptBlock>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
  </ViewDefinitions>
</Configuration>

我使用 ANSI 序列来突出显示 PowerShell 预览和 SSH。我需要做的就是将其导入到我的会话中。

Update-Formatdata c:\scripts\psinstalledinfo.format.ps1xml

现在,我得到了非常有意义的输出。

[玩转系统] 重新审视 PowerShell 版本清单

到你了

我希望你能尝试一下。当然,您还有添加自己的风格的空间。我将 Comments 属性保留为大部分未使用以供将来使用。或者您可能想要获取其他信息,例如文件时间戳。玩得开心。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯