How do you get PowerShell to "see" .NET enum values? - powershell

I'm slowly teaching myself PowerShell and I'm completely baffled by enums. To my understanding, they're just a collection of friendly names for what are really integer values. Okay, ... that's great ... but how do you get PowerShell to actually "see" them?
Example:
[System.Windows.Forms.Application]::EnableVisualStyles();
$form = new-object Windows.Forms.Form
$form.Text = "Image Viewer"
$form.Width = $img.Size.Width;
$form.Height = $img.Size.Height;
$pictureBox = new-object Windows.Forms.PictureBox
$pictureBox.Width = $img.Size.Width;
$pictureBox.Height = $img.Size.Height;
$pictureBox.SizeMode = PictureBoxSizeMode.StretchImage
This would be great if PowerShell had any clue what "PictrueBoxSizeMode.StretchImage" was.
It's a numeric value -- I know that -- you know that -- how do I get PowerShell to know that?
Thanks in advance?

Basic:
[System.Windows.Forms.PictureBoxSizeMode].GetEnumNames()
Advanced (names along with their numeric equivalents):
[System.Enum]::GetNames([System.Windows.Forms.PictureBoxSizeMode])|
ForEach-Object {"{0} {1}" -f
[System.Windows.Forms.PictureBoxSizeMode]::$_.value__, $_ }
Also compare Get-EnumValue function (custom cmdlet) in my answer to Getting enum values of Pseudo-Enum classes at Code Review.
Edit
All above code containing [System.Windows.Forms.PictureBoxSizeMode] run in powershell_ise. Unfortunately, powershell raises TypeNotFound error:
PS D:\PShell> [System.Windows.Forms.PictureBoxSizeMode]::StretchImage
Unable to find type [System.Windows.Forms.PictureBoxSizeMode]. Make sure that the assembly that contains this type is loaded. At line:1 char:1
+ [System.Windows.Forms.PictureBoxSizeMode]::StretchImage
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Windows.Forms.PictureBoxSizeMode:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
We need to renew a reference to System.Windows.Forms namespace; some sources advise renewing a reference to System.Drawing as well:
PS D:\PShell> [void] (Add-Type -AssemblyName System.Windows.Forms -PassThru)
PS D:\PShell> [void] (Add-Type -AssemblyName System.Drawing -PassThru)
PS D:\PShell> [System.Windows.Forms.PictureBoxSizeMode]::StretchImage
StretchImage
PS D:\PShell> [System.Windows.Forms.PictureBoxSizeMode]::StretchImage.value__
1
PS D:\PShell>

Related

Script works in ISE and not SOME powershell CLI

$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("********Please Select the SOURCE Directory********",0,"Directory Selecter 5000",0x1)
Function Get-Folder($initialDirectory)
{
$foldername = New-Object System.Windows.Forms.FolderBrowserDialog
$foldername.rootfolder = "MyComputer"
if($foldername.ShowDialog() -eq "OK")
{
$folder += $foldername.SelectedPath
}
return $folder
}
$a = Get-Folder
$wshellb = New-Object -ComObject Wscript.Shell
$wshellb.Popup("********Please Select the DESTINATION Directory********",0,"Directory Selecter 5000",0x1)
Function Get-Folder($initialDirectory)
{
$foldername = New-Object System.Windows.Forms.FolderBrowserDialog
$foldername.rootfolder = "MyComputer"
if($foldername.ShowDialog() -eq "OK")
{
$folder += $foldername.SelectedPath
}
return $folder
}
$b = Get-Folder
Set-Content -Path "C:\script\scripts\script data.txt" -Value "$a" -Force
Set-Content -Path "C:\script\scripts\script data2.txt" -Value "$b" -Force
So this script works in ISE and if I copy/paste it into a CLI and that's it. If I navigate to the folder in the powershell CLI and run it from there it gives me this error:
New-Object : Cannot find type
[System.Windows.Forms.FolderBrowserDialog]: verify that the assembly
containing this type is loaded. At
C:\script\scripts\pathingworking.ps1:8 char:19
+ $foldername = New-Object System.Windows.Forms.FolderBrowserDialog
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
The property 'rootfolder' cannot be found on this object. Verify that
the property exists and can be set. At
C:\script\scripts\pathingworking.ps1:9 char:5
+ $foldername.rootfolder = "MyComputer"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
You cannot call a method on a null-valued expression. At
C:\script\scripts\pathingworking.ps1:11 char:8
+ if($foldername.ShowDialog() -eq "OK")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
This error comes back twice, once for each instance of the folder selection window that is supposed to pop up.
I have tried -STA from run dialogue, shortcuts, and even from the CLI and it always gives me that error. I have verified using [System.Threading.Thread]::CurrentThread.GetApartmentState() that the open instance of powershell is STA. I can open a powershell CLI and navigate to the folder where the script is, invoke the script, it will give me the error, then I can copy\paste it in the same exact CLI and it works without issue. I have also right-clicked the file in Explorer and selected "run with powershell" and it also gives me the error. I have elevated the CLI to see if that helped with no success.
I fear this is some small oversight and hopefully someone can give me a hand.
using v1.0
windows 10
Cannot find type [System.Windows.Forms.FolderBrowserDialog] is due to the assembly not being loaded.
load the assembly with
Add-Type -AssemblyName "System.Windows.Forms"
rerun's answer solves the errors, but doesn't do a whole lot of explaining. Designing a script in the ISE (which is what I do almost exclusively) is convenient because it will automatically load types and modules for you. If you plan on running the script from another CLI (Command Line Interpreter) you should make it a habit of explicitly loading needed modules and assemblies early on in the script, so that when those things are called upon later PowerShell will know what you're asking for.
Unfortunately there's no easy way to tell what you will need to do that for when it comes to what types are going to be inherently available, but a little trial and error usually points it out rather quickly, or if you look at your script and see that you are making a new object with System.Kitchen.Pasta, then you probably need to load the assembly for System.Kitchen first, so that it has the Pasta type available when you want it, so you could just include a call to load that assembly near the top of the script with no harm done.
In your specific case, as has already been pointed out, you will need to load the assembly that contains the FolderBrowserDialog box that you want to display. Adding the following as the first line of your script will resolve the errors that you are seeing:
Add-Type -AssemblyName "System.Windows.Forms"

How to create Powershell Object with other Objects as Argument

I am trying to write Powershell script for Azure Service Bus Topic Creation. I have similar code in C# which works but now I want to transform it to Powershell script. But right now I am stuck on how to convert following line to Powershell:
AuthorizationRule Ar = new SharedAccessAuthorizationRule("PublisherOwner", "SASKEY++++++++++++++++++++++", new[] { AccessRights.Listen, AccessRights.Send });
I am trying it like this, but it isn't working:
$PublisherRule = New-Object -TypeName Microsoft.ServiceBus.Messaging.SharedAccessAuthorizationRule -ArgumentList "PublisherOwner", $PublisherKey
Here is the Error
New-Object : Cannot find type [Microsoft.ServiceBus.Messaging.SharedAccessAuthorizationRule]: make sure the
assembly containing this type is loaded.
At line:1 char:28
+ $PublisherRule = New-Object <<<< -TypeName Microsoft.ServiceBus.Messaging.SharedAccessAuthorizationRule -
ArgumentList "PublisherOwner", $PublisherKey
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
You can use the array sub-expression operator #() to pass an array as an argument to -ArgumentList:
$PublisherRule = New-Object -TypeName Microsoft.ServiceBus.Messaging.SharedAccessAuthorizationRule -ArgumentList "PublisherOwner", $PublisherKey,#([Microsoft.ServiceBus.Messaging.AccessRights]::Listen,[Microsoft.ServiceBus.Messaging.AccessRights]::Send)
Third parameter the array needs to be a strongly typed array. The converted script is as below and it worked:
[Microsoft.ServiceBus.Messaging.AccessRights[]]$PublisherRights =
New-Object -TypeName "System.Collections.Generic.List[Microsoft.ServiceBus.Messaging.AccessRights]" ;
$PublisherRights += [Microsoft.ServiceBus.Messaging.AccessRights]::Listen;
$PublisherRights += [Microsoft.ServiceBus.Messaging.AccessRights]::Send;
$Rule = New-Object -TypeName Microsoft.ServiceBus.Messaging.SharedAccessAuthorizationRule -ArgumentList "PublisherRule", "SASKEY", $PublisherRights;

PowerShell: cannot convert type SMO.server to type SMO.server

Error I'm getting from PowerShell:
Cannot convert argument "srv", with value: "[DBADEV\SQL2008r2]", for "SqlBackup" to type "Microsoft.SqlServer.Management.Smo.Server": "Cannot convert the "[DBADEV\SQL2008r2]" value of type
"Microsoft.SqlServer.Management.Smo.Server" to type "Microsoft.SqlServer.Management.Smo.Server"."
At line:23 char:1
+ $backup.SqlBackup($srv)
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
I'm attempting to write a PowerShell script to restore a database from our Production box and into our DBADEV box. Below is the code I'm using which is then producing the error.
#Clear Screen
cls
#load assemblies
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
$ErrorActionPreference = "Inquire"
# Restore [SQLSRV2k8-0102\SQL2008] instance
$BackupFile = Get-ChildItem "\\NetworkShare\r`$\MSSQL10.SQL2008\MSSQL\Backup\AdventureWorks2008r2" | select -Last 1
$BackupFile
$srv = New-Object Microsoft.SqlServer.Management.Smo.Server("DBADEV\SQL2008r2")
$res = New-Object Microsoft.SqlServer.Management.Smo.Restore
$backup = New-Object Microsoft.SqlServer.Management.Smo.Backup
$Backup.Devices.AddDevice($BackupFile, [Microsoft.SqlServer.Management.Smo.DeviceType]::File)
$Backup.Database = "AdventureWorks2008r2"
$Backup.Action = [Microsoft.SqlServer.Management.Smo.BackupActionType]::Database
$backup.Initialize = $true
$backup.SqlBackup($srv)
$srv.Databases["AdventureWorks2008r2"].Drop()
$res.Devices.AddDevice($BackupFile, [Microsoft.SqlServer.Management.Smo.DeviceType]::File)
$res.Database = "AdventureWorks2008r2"
$res.NoRecovery = $true
$res.SqlRestore($srv)
The error seems a bit cryptic to me (as do most PowerShell errors). Any thoughts on why this is occurring? I'm also getting the error when I use Mike Fal's powershell script here: http://www.mikefal.net/2014/07/22/restoreautomation-powershell-module/
The one thing that seems to get me past this error is by passing "DBADEV\SQL2008r2" directly into SQLRestore,
i.e. $res.SqlRestore("DBADEV\SQL2008r2") instead of $res.SqlRestore($srv)
This now generate an error stating "Restore failed for Server 'DBADEV\SQL2008r2'
Well from my experiences this kind of errors appear because of wrong name/data type in variable.
I would try to escape \ in "DBADEV\SQL2008r2"
or try what I found on MSDN
$srv = new-Object Microsoft.SqlServer.Management.Smo.Server("(local)")
Write-Host $srv.Information.Version
so it could look like
New-Object Microsoft.SqlServer.Management.Smo.Server("(DBADEV\SQL2008r2)")

Compact & Repair Access 2007 Database with Powershell

I'm trying to use Powershell V2.0 to programatically compact and repair MS Access 2007 (.accdb) databases. The code I've created below works as part of the final code (several backup procedures occur prior to this function running).
I'm running into trouble though as all the databases are password protected and I need to run the script without the user having to enter the passwords manually. Here's my code so far:
Param([string]$strDBPath,[string]$strBUPath,[string]$strPwd)
$ErrorActionPreference = "Stop"
function CompactAndRepairDB {
regsvr32 "C:\Program Files\Common Files\Microsoft Shared\DAO\dao360.dll"
regsvr32 "C:\Program Files\Microsoft Office\Office12\Acedao.dll"
regsvr32 "C:\WINNT\assembly\Microsoft.Office.Interop.Access.Dao\12.0.0.__71e9bce111e9429c\Microsoft.Office.Interop.Access.Dao.dll"
$Database = New-Object -ComObject Microsoft.Office.Interop.Access.Dao.DBEngine
$Database.CompactRepair($strDBPath,$strBUPath,"","",";pwd=" + $strPwd)
Remove-Item $strDBPath
Rename-Item $strBUPath $strDBPath
}
CompactAndRepairDB
The code throws an error though as below:
Cannot load COM type Microsoft.Office.Interop.Access.Dao.DBEngine.
At U:\Scripts\CompactRepairDatabase.ps1:11 char:27
+ $Database = New-Object <<<< -ComObject Microsoft.Office.Interop.Access.Dao.DBEngine
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : CannotLoadComObjectType,Microsoft.PowerShell.Commands.NewObjectCommand
How do I load the correct library / COM object to complete the operation or is there an alternative method to achieve the .CompactRepair method using the password? Thanks
Remove the -ComObject from the line:
$Database = New-Object -ComObject Microsoft.Office.Interop.Access.Dao.DBEngine
Microsoft.Office.Interop.Access.Dao.DBEngine will be a managed interop wrapper around DAO.DBEngine so you don't need the -ComObject switch.
Try this:
Add-Type -AssemblyName Microsoft.Office.Interop.Access
$File = "Your.accdb"
$DbEng = new-object Microsoft.Office.Interop.Access.Dao.DBEngineClass # no square bracket []
$Db = $DbEng.OpenDatabase($File)
$Db

Exception automating Excel 2007 with Powershell when calling Workbooks.Add()

The following code throws an exception in Powershell V1 (Excel 2007):
$E = New-Object -COM "Excel.Application"
$E.Visible = $True
$wb = $E.Workbooks.Add() #<<<Exception here
The error says that the format might be old or that the type library is not valid (translated from Spanish). A similar script for Word works just fine.
Office interop assemblies seem to have this problem when the current culture is not en-US. The obvious workaround is to set the culture.
It's important to run the whole thing as a single command on the interactive console, since PowerShell V1 always creates a new thread for each command invocation.
PS C:\Users\jachymko> $e = new-object -com excel.application
PS C:\Users\jachymko> $e.workbooks.add()
Exception calling "Add" with "0" argument(s): "Old format or invalid type library. (Exception from HRESULT: 0x80028018 (TYPE_E_INVDATAREAD))"
At line:1 char:17
+ $e.workbooks.add <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
PS C:\Users\jachymko> & {
>> [threading.thread]::CurrentThread.CurrentCulture = 'en-US'
>> $e = new-object -com excel.application
>> $e.workbooks.add()
>> $e.visible=1
>> }
>>
Adapted to Powershell from one of the solutions proposed in MS Help and Support Article 320369.
$ci = new-object system.globalization.cultureinfo "en-US"
$e = New-Object -COM "Excel.Application"
$e.Visible = $True
$e.UserControl= $True
$books = $e.Workbooks
$books.PSBase.GetType().InvokeMember( `
"Add", `
[system.reflection.bindingflags]::InvokeMethod, `
$null, $books, $null, $ci)
From the same article:
When you use one of these workarounds for a computer where the regional settings
do not match the current language version of Office, you should be familiar with
how Excel behaves and how Excel will interpret data that might be formatted for
a specific locale.
I had this issue when trying to open a workbook. I added this line:
[threading.thread]::CurrentThread.CurrentCulture = 'en-US'