Archive for the ‘Scripts’ Category

Powershell – Hyper-V get VM IP config

Posted: February 28, 2020 in Scripts

Prerequisite:

Install Integration services on VM

This script will get IPV4 only IP address, VM name and MAC address.

: will be added to MAC address. In case VM has more than one IP/MAC, those values will be in same column separated by space

# Get all running VMs

$vms = Get-VM | Where { $_.State –eq ‘Running’ } | Select-Object -ExpandProperty Name 

# Declare "global" array variable (make it available outside loop)

$results = @()
 foreach($vm in $vms) {

    # Get network interface details
    $out = Get-VMNetworkAdapter -vmname $vm | select VMName, MacAddress, IPAddresses

    # Remove duplicate VM names
    $vm_name = $out.VMName | Get-Unique

    # In case more than 1 IP, put it in same row separated by space (192.168.1.1, 192.168.1.2)
    
    $ip = ($out.IPAddresses | ForEach-Object {
    $_ | ? {$_ -notmatch ':'}   
    }) -join " "

    # If more than 1 MAC , put it in same row separated by space (00:15:5D:58:12:5E 00:15:5D:58:12:5F )
    
    $mac = ($out.MacAddress | ForEach-Object {
    $_.Insert(2,":").Insert(5,":").Insert(8,":").Insert(11,":").Insert(14,":")
}) -join ' '
     
  # Add headers
   
$comp = Get-WmiObject Win32_ComputerSystem | Select-Object -ExpandProperty name

$obj = New-Object -TypeName psobject
$obj | Add-Member -MemberType NoteProperty -Name "VM NAME" -Value $vm_name
$obj | Add-Member -MemberType NoteProperty -Name "IP ADDRESS" -Value $ip
$obj | Add-Member -MemberType NoteProperty -Name "MAC ADDRESS" -Value $mac
$obj | Add-Member -MemberType NoteProperty -Name "HYPER-V HOST" -Value $comp

# Append object to outside "global" variable

$results += $obj

#$obj| Export-Csv -Path "c:\1.csv" -NoTypeInformation -append 
}

# write results to CSV file
                                
$results| Export-Csv -Path "c:\1.csv" -NoTypeInformation
 

Option 2: multi-line (every IP/MAC) have new line

$results = Get-VM | Where State –eq Running | Get-VMNetworkAdapter | ForEach-Object {
    [pscustomobject]@{
        'VM NAME'      = $_.VMName
        'IP ADDRESS'   = ($_.IPAddresses -notmatch ':') -join ' '
        'MAC ADDRESS'  = ($_.MacAddress -replace '(..)(..)(..)(..)(..)','$1:$2:$3:$4:$5:') -join ' '
        'HYPER-V HOST' = $env:COMPUTERNAME
    }
}
$results | Export-Csv -Path "c:\1.csv" -NoTypeInformation

# Put in single row multiple IP/MAC addresses for one VM:

$csv = $results | Group-Object 'VM NAME'  | ForEach-Object {
 [PsCustomObject]@{
 'VM NAME' = $_.Name
 'IP ADDRESS' = $_.Group.'IP ADDRESS' -join ' '
 'MAC ADDRESS' = $_.Group.'MAC ADDRESS' -join ' '
 }
}
$csv | Export-Csv -Path "c:\1.csv" -NoTypeInformation

When trying to move files in python, if, for destination, only folder is specified, and if file already exist in destination, python will raise an error that file already exists.

import shutil
import os

source = "C:\Users\user\Downloads\python-2.7.17.msi"
destination = "C:\Users\user\Desktop"
shutil.move(source, destination)

raise Error, "Destination path '%s' already exists" % real_dst
shutil.Error: Destination path 'C:\Users\user\Desktop\python-2.7.17.msi' already exists

In order to overwrite file (if one already exists in destination), we need to specify full path for destination,not only destination folder name, for example C:\Users\user\Downloads\python-2.7.17.msi

import shutil
import os

source = "C:\Users\user\Downloads\python-2.7.17.msi"
destination = "C:\Users\user\Desktop"
filename = os.path.basename(source)
dest = os.path.join(destination,filename)
shutil.move(source, dest)

Usernames and passwords are stored in CSV file:

1.csv:

link,user,password
http://1.1.1.1,user1,password1
http://2.2.2.2,user2,password2

We can extract link,user and password using this Powershell script:

# Constants.
$DELIM = ','
$CSV_F = 'C:\Users\user\Desktop\1.csv' 

# Parse keys
$keys = (gc "${CSV_F}" -TotalCount 1).Split($DELIM)
$csv = Import-CSV "${CSV_F}"
$data = @()

# Iterate through CSV to build array of hashtables.
ForEach ($r in $csv) {
    $tmp_h = @{}

    # Create hash of key-value pairs.
    ForEach($k in $keys) {
        $tmp_h[$k] = $r.($k)
    }

    # Add hash to array of hashes.
    $data += $tmp_h
}
# Display data
foreach($i in $data){
$link = $i.link
$user = $i.user
$password = $i.password
}

Encrypting CSV file

Because this file contains sensitive data, it would be reasonable to encrypt it.We’ll use Protect-CmsMessage cmd-let to achieve that.

Create a certificate for encrypting content

In Powershell console paste certificate request (change subject name and.or inf file name):

# Create .INF file for certreq

{[Version]
Signature = "$Windows NT$"

[Strings]
szOID_ENHANCED_KEY_USAGE = "2.5.29.37"
szOID_DOCUMENT_ENCRYPTION = "1.3.6.1.4.1.311.80.1"

[NewRequest]
Subject = "cn=youralias@emailaddress.com"
MachineKeySet = false
KeyLength = 2048
KeySpec = AT_KEYEXCHANGE
HashAlgorithm = Sha1
Exportable = true
RequestType = Cert
KeyUsage = "CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DATA_ENCIPHERMENT_KEY_USAGE"
ValidityPeriod = "Years"
ValidityPeriodUnits = "1000"

[Extensions]
%szOID_ENHANCED_KEY_USAGE% = "{text}%szOID_DOCUMENT_ENCRYPTION%"
} | Out-File -FilePath DocumentEncryption.inf

After you have created your certificate file, run the following command to add the certificate file to the certificate store.

Only user(s) who have access to this certificate can encrypt/decrypt files.

certreq -new DocumentEncryption.inf DocumentEncryption.cer 

Encrypt CSV file using certificate subject or OID number:

Protect-CmsMessage -To "*youralias@emailaddress.com*" -Path C:\Users\user\Desktop\1.csv -OutFile C:\Users\user\Desktop\1.csv.cms

Following script will decrypt CSV “on the fly”, and store it’s content into $CSV_F variable, avoiding storing un-encrypted CSV file.

$CSV_F = Unprotect-CmsMessage -To "*youralias@emailaddress.com*" -Path .\1.csv.cms 

$Data = $CSV_F | ConvertFrom-Csv
foreach($i in $Data){

$link = $i.link

$user = $i.user

$password = $i.password

}

Script for concatenating first_name, last_name and address into ResourceName column, and return column which contain Dylan Dog Craven Road rows.

 

Capture

Import-Csv "C:\1.csv" | Select-Object  @{n='ResourceName';e={$_.FIRST_NAME + "," + $_.LAST_NAME + "," + $_.ADDRESS}} `
| Where-Object {$_.ResourceName -like "Dylan*Dog*Craven Road 7"}

Result:

ResourceName
------------------
Dylan,Dog,Craven Road 7

Recently i got long list of linux machines and had to check which of them support password authentication.

I found a tool Hydra , if it finds machine which do not support password authentication, it will print it in output

Hydra v8.2-dev (c) 2016 by van Hauser/THC - Please do not use in military
or secret service organizations, or for illegal purposes. Hydra
(http://www.thc.org/thc-hydra) starting at 2019-11-25 14:49:59 [DATA]
max 4 tasks per 4 servers, overall 64 tasks, 5 login tries (l:1/p:5),
~0 tries

per task [DATA] attacking service ssh on port 22
[ERROR] target ssh://1.1.1.1:22/ does not support password authentication.
[ERROR] target ssh://2.2.2.2:22/ does not support password authentication.

ERROR] target ssh://3.3.3.3:22/ does not support password authentication.

[ERROR] target ssh://4.4.4.4:22/ does not support password authentication.

4 of 4 targets completed, 0 valid passwords found Hydra 

(http://www.thc.org/thc-hydra) finished at 2019-11-25 14:50:01

So i created simple batch script which captures Hydra output into $command variable, then get string between [ERROR] target ssh:// and :22/ does not support into $out variable.

Then get IP address of masines – $filtered variable. Then print every IP into new line and write it to output.txt file.

Installing hydra (CentOS 7)

rpm -Uvh http://www6.atomicorp.com/channels/atomic/centos/7/x86_64/RPMS/atomic-release-1.0-21.art.noarch.rpm
yum install hydra

Put all your passwords to file pws.txt and machines IP into targets.txt

file: put every password/IP into new line

command=$((hydra -l root -P pws.txt -M targets.txt ssh -t 4) 2>&1)
echo $command
out=$(echo $command | grep -oP '(?<=ERROR] target ssh://).*(?=:22/ does not support)')
filtered=$(echo "$out" | sed 's|does not support password authentication.||g ; s|/||g ; s|ERROR||g ; s|target ssh||g ; s|:22||g ; s/[][]//g ; s|/||g ; s|:||g')
echo $filtered | xargs -n1 > output.txt

output.txt will contain IPs of machine which don’t support password authentication.

This script will ping IP 1.1.1.1, if ping fails, and if ping to 2.2.2.2 is successful, and if there is host A record for IP 1.1.1.1,it will change DNS record to match 2.2.2.2

function Switch-IP {
    [CmdletBinding()]
    param (
    
    [Parameter(Mandatory=$true][string]$IP,[Parameter(Mandatory=$true][string] $newIP
        )
  
    $currentIP = $oldobj.RecordData | select IPv4Address
    if ($currentIP.IPv4Address.IPAddressToString -eq $IP) {
         
    $newobj = get-dnsserverresourcerecord -name "nagios" -zonename "test.local" -rrtype "A"
    $updateip = $newIP
    $newobj.recorddata.ipv4address=[System.Net.IPAddress]::parse($updateip)
    Set-dnsserverresourcerecord -newinputobject $newobj -OldInputObject $oldobj -zonename "test.local" -passthru > C:\dnsfailover.log
    add-content -path C:\dnsfailover.log -Value $(Get-Date)
    }
    }

 $IP = "1.1.1.1"
 $newIP = "2.2.2.2"
 
    if (-Not (test-connection $IP -Quiet -Count 1)) {
    if (test-connection $newIP -Quiet -Count 1) { 

    $oldobj = get-dnsserverresourcerecord -name "nagios" -zonename "test.local" -rrtype "A"
 
    $currentIP = $oldobj.RecordData | select IPv4Address
    if ($currentIP.IPv4Address.IPAddressToString -eq $IP) {
         
    Switch-IP $IP $newIP
      
    }
 
}}
 
 
elseif ((test-connection $newIP -Quiet -Count 1) -and (test-connection $IP -Quiet -Count 1)) {
 
  
    $oldobj = get-dnsserverresourcerecord -name "nagios" -zonename "test.local" -rrtype "A"
 
    $currentIP = $oldobj.RecordData | select IPv4Address
    if ($currentIP.IPv4Address.IPAddressToString -eq $newIP) {
       
    Switch-IP $newIP $IP    
        
  }
 }
 

Next example assumes that there are 2 DNS records with same name (nagios), one record has IP 1.1.1.1, and second one is 2.2.2.2.

If ping to 1.1.1.1 fails, and if there are 2 DNS entries for host nagios, remove DNS entry for IP 1.1.1.1. When connection is restored, add back DNS entry for 1.1.1.1

$dnszone = "test.local"
$currentRecord = Get-DnsServerResourceRecord -name "nagios" -ZoneName $dnszone -RRType A 
$currentIP = $currentRecord.RecordData | select IPv4Address
$primaryIP = "1.1.1.1"
$secondaryIP = "2.2.2.2"    
    
    if (-Not (test-connection $primaryIP -Quiet -Count 1)) {
 
       if (test-connection $secondaryIP -Quiet -Count 1) { 
 
 
             if ($currentIP.Count -eq 2)  {
 
          try {
 
         Remove-DnsServerResourceRecord -name "nagios" -ZoneName $dnszone -RRType A -RecordData $primaryIP -Force -ErrorAction Stop -PassThru  > C:\dnsfailover.log  
         add-content -path C:\dnsfailover.log -Value "$(Get-Date):DNS entry removed" 
            }
 
          catch { 
          $Error[0].Exception.Message
                 }
 
 
    }}}
 
 
 
    elseif ((test-connection $secondaryIP -Quiet -Count 1) -and (test-connection $primaryIP -Quiet -Count 1)) {
 
  
           $currentRecord = Get-DnsServerResourceRecord -name "nagios" -ZoneName $dnszone -RRType A 
           $currentIP = $currentRecord.RecordData | select IPv4Address
    
        if  ($currentIP.Count -ne 2) {
 
        try {
 
         Add-DnsServerResourceRecord -A -Name "nagios" -ZoneName $dnszone -IPv4Address $primaryIP -TimeToLive 00:00:10 -PassThru  > C:\dnsfailover.log  
         add-content -path C:\dnsfailover.log -Value "$(Get-Date):DNS entry added" 
         }
 
         catch {
         $Error[0].Exception.Message
              }
       
      
  }
  
}

Following script will loop through all Partner Center customers, will export them in batches of 100 and every “chunk” will be exported to separate CSV file.

 

$custIDs = Get-PartnerCustomer
$chunks = [System.Collections.ArrayList]::new()
for ($i = 0; $i -lt $custIDs.Count; $i += 100) {
    if (($custIDs.Count - $i) -gt 99  ) {
        $chunks.add($custIDs[$i..($i + 99)])
    }
    else {
        $chunks.add($custIDs[$i..($custIDs.Count - 1)])
    }
}
$today = [datetime]::Today.ToString("yyyy-MM-dd")
$count = 1
foreach ($chunk in $chunks) {
    $path = "c:\Reports\$today Chunk $count of $($chunks.Count).csv"
    $chunk | Export-Csv $path -Append
    $count++
}