Is there a way to find every single modules which will be needed in script? - powershell

I'd like to use a kinda analyzer which will install/import all the needed modules by the script before I run it on distant machine (which could not have it) ......
any idea ?
EDIT
Here's the case :
I'm on my dev machine, I'ved already installed lots of modules of all kind (dhcp, ntfs, remoting, register, etc.)
When I finally got my script (which is a function) to work, I can't be sure of what modules are used....
What I want is to write down, in the 'begin' section, the correct imports before I send my script on remote PCs; to be sure it's gonna run perfectly, you follow ?...
Is there a kinda a third party appplication which can scan my script and give me all needed modules ?

You could do something like this to get help in finding commands used and their source/module names. It's very unpolished, just trying to give the idea.
$scriptblock = {
Write-Host "Nothing here"
$files = Get-ChildItem c:\temp
Get-ADUser someuser
Test-NetConnection www.google.com
}
# Uncomment following lines and enter the path to your script file
# $scriptFile = "Path\to\some\scriptfile"
# $scriptblock = [scriptblock]::Create((Get-Content -raw -Path $scriptFile))
$ast = $scriptblock.Ast
$commands = $ast.FindAll( { $args[0] -is [System.Management.Automation.Language.CommandAst] }, $true)
$commandText = foreach ($command in $commands) {
$command.CommandElements[0].Extent.Text
}
$commandText |
Select-Object -Unique |
Sort-Object |
Select-Object #{
Label = "CommandName"
Expression = { $_ }
},
#{
Label = "Source"
Expression = {
(Get-Command $_).Source
}
}
Output
CommandName Source
----------- ------
Get-ADUser ActiveDirectory
Get-ChildItem Microsoft.PowerShell.Management
Test-NetConnection NetTCPIP
Write-Host Microsoft.PowerShell.Utility

Yeah, you could for example test if the module exists on that particular machine by trying to import it as follows
Try {
Import-Module dbaclone -ErrorAction stop
#ErrorAction required as failing to import is not a terminating action
} Catch {
Write-Verbose -Verbose "Failed to find dbaclone module - installing"
Install-Module dbaclone -AllowClobber -Force
Write-Verbose -Verbose "Installed!"
Import-Module dbaclone
}

Related

Check function exists in PowerShell module

I’ve the following PowerShell script which searches in a directory for PowerShell module). All found modules will be imported and stored in a list (using the -PassThru) option.
The scrip iterates over the imported modules and invokes a function defined in the module:
# Discover and import all modules
$modules = New-Object System.Collections.Generic.List[System.Management.Automation.PSModuleInfo]
$moduleFiles = Get-ChildItem -Recurse -Path "$PSScriptRoot\MyModules\" -Filter "Module.psm1"
foreach( $x in $moduleFiles ) {
$modules.Add( (Import-Module -Name $x.FullName -PassThru) )
}
# All configuration values
$config = #{
KeyA = "ValueA"
KeyB = "ValueB"
KeyC = "ValueC"
}
# Invoke 'FunctionDefinedInModule' of each module
foreach( $module in $modules ) {
# TODO: Check function 'FunctionDefinedInModule' exists in module '$module '
& $module FunctionDefinedInModule $config
}
Now I would like to first check if a function is defined in a module before it gets invoked.
How can such a check be implemented?
The reason for adding the check if to avoid the exception thrown when calling a function which doesn’t exists:
& : The term ‘FunctionDefinedInModule’ is not recognized as the name of a cmdlet, function, script file, or operable program
Get-Command can tell you this. You can even use module scope to be sure it comes from a specific module
get-command activedirectory\get-aduser -erroraction silentlycontinue
For example. Evaluate that in an if statement and you should be good to go.
Use Get-Command to check if a function currently exists
if (Get-Command 'FunctionDefinedInModule' -errorAction SilentlyContinue) {
"FunctionDefinedInModule exists"
}
If many functions need to be checked
try{
get-command -Name Get-MyFunction -ErrorAction Stop
get-command -Name Get-MyFunction2 -ErrorAction Stop
}
catch{
Write-host "Load Functions first prior to laod the current script"
}
I needed it so often that I wrote module for this.
Maybe try adding this function to your module?
function DoesFunctionExists {
param(
[string]$Function
)
$FunList = gci function:$Function -ErrorAction 'SilentlyContinue'
foreach ($FunItem in $FunList) {
if ($FunItem.Name -eq $Function) {
return $true
}
}
return $false
}

Missing AD module and can't get it, need something similar or something to simulate it

So I'm trying to output a complete KB list for all computers on a server (which works on one computer) but it doesn't recognize Get-ADcomputer as a cmdlet. When checking various sources, it appears that the AD module isn't included. As I'm doing this on a work computer/server I'm hesitant to download anything or anything of that nature.
Is there any way I can achieve the following without using the AD module or someway I might be missing how to import the module (if it exists, which I don't think it does on this system)?
# 1. Define credentials
$cred = Get-Credential
# 2. Define a scriptblock
$sb = {
$Session = New-Object -ComObject Microsoft.Update.Session
$Searcher = $Session.CreateUpdateSearcher()
$HistoryCount = $Searcher.GetTotalHistoryCount()
$Searcher.QueryHistory(0,$HistoryCount) | ForEach-Object -Process {
$Title = $null
if ($_.Title -match "\(KB\d{6,7}\)") {
# Split returns an array of strings
$Title = ($_.Title -split '.*\((?<KB>KB\d{6,7})\)')[1]
} else {
$Title = $_.Title
}
$Result = $null
switch ($_.ResultCode) {
0 { $Result = 'NotStarted'}
1 { $Result = 'InProgress' }
2 { $Result = 'Succeeded' }
3 { $Result = 'SucceededWithErrors' }
4 { $Result = 'Failed' }
5 { $Result = 'Aborted' }
default { $Result = $_ }
}
New-Object -TypeName PSObject -Property #{
InstalledOn = Get-Date -Date $_.Date;
Title = $Title;
Name = $_.Title;
Status = $Result
}
} | Sort-Object -Descending:$false -Property InstalledOn | Where {
$_.Title -notmatch "^Definition\sUpdate"
}
}
#Get all servers in your AD (if less than 10000)
Get-ADComputer -ResultPageSize 10000 -SearchScope Subtree -Filter {
(OperatingSystem -like "Windows*Server*")
} | ForEach-Object {
# Get the computername from the AD object
$computer = $_.Name
# Create a hash table for splatting
$HT = #{
ComputerName = $computer ;
ScriptBlock = $sb ;
Credential = $cred;
ErrorAction = "Stop";
}
# Execute the code on remote computers
try {
Invoke-Command #HT
} catch {
Write-Warning -Message "Failed to execute on $computer because $($_.Exception.Message)"
}
} | Format-Table PSComputerName,Title,Status,InstalledOn,Name -AutoSize
You've got 3 options:
First is to just install the RSAT feature for AD which will include the AD module. This is probably the best option unless there is something specific preventing it. If you're running your script from a client operating systems you need to install the RSAT first, though.
Option 2 (which should only be used if adding the Windows feature is somehow an issue) is to download and use the Quest AD tools, which give very similar functionality, but it looks like Dell is doing their best to hide these now so that may be difficult to locate...
Option 3 is to use the .NET ADSI classes to access AD directly, which will work without any additional downloads on any system capable of running PowerShell. If you'd like to go this route you should check out the documentation for the interface Here and for the System.DirectoryServices namespace Here.
Edit
Just noticed the last part of your question, what do you mean by "a complete KB list"? Not just Windows updates or things updated manually or whatever? What else would be in a list of Windows updates that was not a Windows update?
You have not mentioned the OSes you are using but in general if you have a server 2008 R2 or above, all you have to do it activate the RSAT feature AD PowerShell Module and you will have the cmdlet you are looking for.
On a client machine, you 'have to' install RSAT, and then activate the features. You can take a look at the technet article for more info: https://technet.microsoft.com/en-us/library/ee449483(v=ws.10).aspx
If you don't want to use that option, then you will have to use .NET ADSI classes. There are tons of examples on how to do this, it basically boils down to a couple of lines really. Technet has examples on this as well: https://technet.microsoft.com/en-us/library/ff730967.aspx

IF Statement to Verify VLAN Exists in PowerCLI Script

I am writing a PowerCLI script to automate the creation of VMs based on the data within a CSV file and I would like to know how to format an IF statement to check if the VLANs specified already exist to avoid cluttering up the screen with errors.
The section of the script dealing with the VLAN creation in its current format:
New-VM -Name $_.Name -VMHost ($esx | Get-Random) -NumCPU $_.NumCPU -Location $Folder
$list = Get-Cluster $_.Cluster | Get-VMHost
foreach ($esxhost in $list)
{ Get-VirtualSwitch -Name $switch -VMHost $esxhost |
New-VirtualPortgroup -Name "VLAN $($_.VLAN)" -VLANID $($_.VLAN)
}
Write-Host "Wait - propagating VLAN $($_.VLAN) to all hosts" -foreground yellow
Start-Sleep 10
I would like to determine a way to have the script do something like:
IF $_.VLAN exists
Write-host "$_.VLAN already present, proceeding to next step"
ELSE DO{ Get-VirtualSwitch -Name $switch -VMHost $esxhost |
New-VirtualPortgroup -Name "VLAN $($_.VLAN)" -VLANID $($_.VLAN)
}
I don't have much experience in writing these so I was hoping for some assistance on how to
Check whether the VLAN already exists in vSphere on the switch
How to format the IF/ELSE statement properly to avoid cluttering up the PowerCLI window with errors when the script is run
Thank you for any assistance you may provide
EDIT to work for vlan rather than vswitch
You could use get-virtualportgroup for this and check if the names returned contain your vlanid. This won't work for distributed switches as that's a different set of cmdlets.
$host = 'YourHost'
$vlanid = 'YourVlanId'
if ((Get-VirtualPortGroup -host $host).VLanId -contains $vlanid )
{
Write-Output 'vlan present'
}
else
{
Write-Output 'vlan missing'
#your code to create vlan here
}

Remote Powershell return value

I want to run a powershell with WinRM on serveral servers. I am using Invoke-Command with a script block.
I am reading from IIS and want to return a AppPool-Object, but I cannot access its properties - always empty.
#--imagine this code in a foreach block
$result = Invoke-Command -ComputerName $line.Servername -ScriptBlock {
Import-Module WebAdministration
$remotePoolName = Get-Item "IIS:\Sites\LeSite" #| Select-Object applictionPool
$pool = dir IIS:\AppPools | Where-Object { $_.Name -eq $remotePoolName.applicationPool }
return $pool
}
write-host $result.managedRuntimeVersion <- empty
Do I have to access it on the remote machine and return it as string ?
The problem here is, that you are referring to a property including get and set functions.
Using these functions outside of your server area results in nothing since the object is no longer in your server environment.
Using these functions inside your script block will work, because you use them on your server directly.
Greetz

perform nslookup from PowerShell

I'm writing a powershell to exact the ip from a server name, which need me to embed the nslookup code into my powershell
how can I do the intergrating work?
Can any body help me?
Add-PSSnapin Microsoft.SharePoint.PowerShell
$web = Get-SPWeb -Identity “http://nycs00058260/sites/usitp“
$server_status = "PROD"
$list=$web.Lists[”DNS_Status”]
$items = $list.items
Foreach($item in $items){
$item_name = $item["Server_name"] #need to get the ip by this name
/*nslook up*/
$item_name.update()
}
If you install the PSCX module, it comes with a cmdlet Resolve-Host which handles name lookups.
Absent that, this one-liner will do the job
[System.Net.Dns]::GetHostAddresses("www.msn.com")
You can also pass in an IP address - but the results will be different.
See also http://blogs.msdn.com/b/powershell/archive/2006/06/26/647318.aspx & http://powershell.com/cs/media/p/210.aspx
PowerShell 3.0 on Windows 8 and higher comes with a Resolve-DnsName cmdlet that will get this information:
(Resolve-DnsName $server_name)[0].IpAddress
Simply use :
Resolve-DnsName monServer | ? { # make selection here } | % { $_.IPAdress } | select-object -first 1
#Here is a far better method for nslookup
# HOWTO ensure an nslookup results no errors but still gives the original names and column separations
$day = Get-Date -Format yyyyMMdd #<-- HOWTO set the day variable for today
$ErrorActionPreference = ‘SilentlyContinue’ #<-- HOWTO turn off error messages
$WarningActionPreference = 'SilentlyContinue' #<-- HOWTO turn off warning messages
$servers = Get-Content .\input\servers.txt
Foreach ($server in $servers){
$result = Resolve-DnsName $server -Server $env:LOGONSERVER.Remove(0,2) -Type ALL #<-- NSLOOKUP using your logon server
write-host ($server+","+$result.Name+","+$result.IPAddress) #<-- HOWTO Write two variables separated by a comma
}
$ErrorActionPreference = ‘SilentlyContinue’ #HOWTO turn on error messages
$WarningActionPreference = 'SilentlyContinue' #HOWTO turn on warning messages