PowerShell script fails first time but works second time - scripting

I've found a PowerShell script that can change the desktop wallpaper of my Windows 7 PC of an image file whose path is supplied as a parameter. The end result of what I want is to have this script called by a batch file on startup.
[CmdletBinding()]
Param(
[Parameter(Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
[Alias("FullName")]
[string]
$Path
,
[Parameter(Position=1, Mandatory=$false)]
$Style = "NoChange"
)
BEGIN {
try {
$WP = [Wallpaper.Setter]
} catch {
$WP = add-type #"
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace Wallpaper
{
public enum Style : int
{
Tile, Center, Stretch, NoChange
}
public class Setter {
public const int SetDesktopWallpaper = 20;
public const int UpdateIniFile = 0x01;
public const int SendWinIniChange = 0x02;
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int SystemParametersInfo (int uAction, int uParam, string lpvParam, int fuWinIni);
public static void SetWallpaper ( string path, Wallpaper.Style style ) {
SystemParametersInfo( SetDesktopWallpaper, 0, path, UpdateIniFile | SendWinIniChange );
RegistryKey key = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop", true);
switch( style )
{
case Style.Stretch :
key.SetValue(#"WallpaperStyle", "2") ;
key.SetValue(#"TileWallpaper", "0") ;
break;
case Style.Center :
key.SetValue(#"WallpaperStyle", "1") ;
key.SetValue(#"TileWallpaper", "0") ;
break;
case Style.Tile :
key.SetValue(#"WallpaperStyle", "1") ;
key.SetValue(#"TileWallpaper", "1") ;
break;
case Style.NoChange :
break;
}
key.Close();
}
}
}
"# -Passthru
}
}
PROCESS {
Write-Verbose "Setting Wallpaper ($Style) to $(Convert-Path $Path)"
$WP::SetWallpaper( (Convert-Path $Path), $Style )
}
I'm calling this script using the command:
C:\scripts\Set-Wallpaper.ps1 C:\Users\myProfile\Pictures\MyWallpaper.jpg
I'm totally new to the world of PowerShell scripts, and the issue I'm having is that when I execute the script from within PowerShell it always fails the first time with the following error:
C:\scripts\Set-Wallpaper.ps1 : Unable
to cast object of type
'System.Object[]' to type
'System.Type'.
At line:1 char:29
C:\scripts\Set-Wallpaper.ps1 <<<< C:\Users\mbaleato\Pictures\MyWallpaper.jpg
CategoryInfo : NotSpecified: (:) [Set-Wallpaper.ps1],
InvalidCastException
FullyQualifiedErrorId : System.InvalidCastException,Set-Wallpaper.ps1
But when I call the script with the exact same command and parameter the second time it works.
It is this failing the first time that is causing my batch file to fail.
Anyone who is more experienced have some suggestions as to why it fails the first time, but works the second time? Any suggestions as to how I can get it to work the first time?

Look at line that begins with $WP = add-type #". That's the problem. You create two types:
$wp
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Style System.Enum
True False Setter System.Object
Try to call Add-Type without -Passthru and after that assign to $wp
Add-Type -typedef #"
...
"#
$WP = [Wallpaper.Setter]

I believe it's because-passthru is making $WP into an array - you could try this try this instead:
try {
$WP = [Wallpaper.Setter]
} catch {
add-type #"
....
"#
$WP = [Wallpaper.Setter]
}
You can see by running it line by line and checking the tyoe:
PS D:\bin\OpenSSL-Win32\bin> $WP
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Style System.Enum
True False Setter System.Object
PS D:\bin\OpenSSL-Win32\bin> $WP.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
PS D:\bin\OpenSSL-Win32\bin> $WP = [Wallpaper.Setter]
PS D:\bin\OpenSSL-Win32\bin> $WP.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
False True RuntimeType System.Type
The second time around the type is already there so %WP is loaded correctly.

Inside Powershell script :
PS c:\> & 'C:\scripts\Set-Wallpaper.ps1' C:\Users\myProfile\Pictures\MyWallpaper.jpg
From cmd.exe
C:\> PowerShell -command "& 'C:\scripts\Set-Wallpaper.ps1' C:\Users\myProfile\Pictures\MyWallpaper.jpg"

Related

Editor.GetEntity does not wait for user input (click)

I have two dwg files: PID.dwg & 3D.dwg
The use case is to run a function on PID.dwg and then on 3D.dwg -- particularly in this order.
The commands used in SendCommand below are from a separate DLL file that I load using NETLOAD prior to this function's execution.
Dim app As AcadApplication = CType(Application.AcadApplication, AcadApplication)
' Ctype( Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication,
' Autodesk.AutoCAD.Interop.AcadApplication )
If isPidAnd3dOpened() Then
' Activate PID document
app.ActiveDocument = acDocPid
'acDocPid.Activate()
acDocPid.SendCommand("DOSOMETHINGONPID" & vbCrLf)
' Activate 3D document
app.ActiveDocument = acDoc3d
'acDoc3d.Activate()
acDoc3d.SendCommand("DOSOMETHINGON3D" & vbCrLf)
End If
The function of "DOSOMETINGON3D" requires and input from the user using Editor.GetEntity.
However, when acDoc3d.SendCommand("DOSOMETHINGON3D" & vbCrLf) is executed, it does not pause to wait for user input.
What am I missing?
Probably You have to wait until the command DOSOMETHINGONPID is finished.
In ARX it would be something like this:
CString activeCMDName = _T("DOSOMETHINGONPID");
bool EOL = false;
while (!EOL)
{
CString cmds = Variable::Get(_T("CMDNAMES") );
if (cmds.Find( activeCMDName ) > 0 ) {
Command::Wait();
}
else {
EOL = true;
}
}
where
CString Variable::Get( CString name )
{
CString OutVal;
resbuf rb ;
acedGetVar(name, &rb);
OutVal.SetString(rb.resval.rstring);
acutDelString(rb.resval.rstring);
return OutVal ;
}
void Command::Wait()
{
ResBuf rb;
rb.Add(RTSTR , _T("\\"));
int ret = acedCmd(rb.GetFirst());
}
Sorry, I don't have this code in .net. Hope You will handle this.
First answer is correct, SendCommand cannot handle asynchronous commands. Here is a suggested solution in .Net:
//Create AutoCAD instance, then...
acadApp.ActiveDocument.SendCommand("(command \"NETLOAD\""+#"""C:\\acad\\networkdll\\SecondAssembly.dll"") ");
acadApp.ActiveDocument.SendCommand("#MYCOMMAND 0 ");
//Register EndCommand handler.
_DAcadApplicationEvents_EndCommandEventHandler handler = new
_DAcadApplicationEvents_EndCommandEventHandler(CommandEnded);
acadApp.EndCommand += handler;
waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
waitHandle.WaitOne();
acadApp.EndCommand -= handler;
//Close the startup drawing (this requires waiting # SendCommand) because
//Drawing will cause a COMException otherwise. 'Drawing is busy'
//Mostly likely since the ActiceDocument is the startup drawing.
Event Handler:
public void CommandEnded(string globalCommandName)
{
System.Windows.MessageBox.Show(globalCommandName + " just ended.");
waitHandle.Set();
}

Inconsistent behavior when executing New-WebServiceProxy in a loop

I'm having a problem with a powershell script that I wrote to call a method on a WCF web service. The WCF service has a composite DataContract as its sole request parameter. We have recently modified the ServiceContract (by adding two new methods), but the new methods are not being called by the powershell script. Here is the original contract:
[ServiceContract]
public interface IFileSystemService {
[OperationContract]
HashFileResponse HashFile(HashFileRequest req);
[OperationContract]
void GenerateFiles(GenerateFilesRequest req);
}
And here is the new contract:
[ServiceContract]
public interface IFileSystemService {
[OperationContract]
HashFileResponse HashFile(HashFileRequest req);
[OperationContract]
void GenerateFiles(GenerateFilesRequest req);
[OperationContract]
ParseFilePathResponse ParseFilePath(ParseFilePathRequest req);
[OperationContract]
ArchiveParsedFileResponse ArchiveParsedFile(ArchiveParsedFileRequest req);
}
The GenerateFiles method is the one being called by the PowerShell script. We have not modified the GenerateFilesRequest DataContract at all, which is defined below:
[DataContract]
public class GenerateFilesRequest : BaseRequest {
[DataMember(IsRequired = true)]
public int Id { get; set; }
}
Baserequest is currently an empty class for future use (all our request data contracts use it):
[DataContract]
public abstract class BaseRequest {
}
Calling this method works consistently via other means; SoapUI, Fiddler and via WCF contracts defined throughout the application.
After adding the two new methods, our integration tests are failing due to the fact the powershell script fails to call the GenerateFiles method consistently within a loop (see error output).
When I initially wrote this script, I was having a similar issue running it (though it either consistently broke, or consistently worked) but I managed to get the service calls working by adding the -Namespace and -Class arguments to the New-WebServiceProxy cmdlet.
Context: We are running a powershell script on a developer's machine, connecting to a WCF service hosted in IISExpress. All developers experience the same issues.
Here's the original script (preferred) before my recent modifications (this was working fine, but now most calls fail):
$sqlServer=$args[0]
function CallFSS($Id) {
$uri = "http://localhost:1234/FileSystemService.svc?wsdl"
$srv = New-WebServiceProxy -Uri $uri -Namespace fssNS -Class fssClass
$req = [fssNS.GenerateFilesRequest](New-Object fssNS.GenerateFilesRequest)
$req.Id= $Id
$response = $srv.GenerateFiles($req)
}
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=" + $sqlServer + ";Database=MyDatabase;Integrated Security=True"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "select Id FROM MyTable WHERE Status = 2"
$SqlCmd.Connection = $SqlConnection
$sqlResult = $SqlCmd.ExecuteReader()
while ($sqlResult.Read()) {
$Id = $sqlResult.GetInt32(0)
Write-Host Generating files for Id $Id
CallFSS $Id
}
$SqlCmd.Dispose()
$SqlConnection.Dispose()
$SqlConnection.Close()
Here is an excerpt of the output from the script. As you can see, this is vastly inconsistent (Lines marked like this succeed):
Generating files for Id 1
Cannot convert argument "req", with value: "fssNS.GenerateFilesRequest", for "GenerateFiles" to type "fssNS.GenerateFilesRequest": "Cannot convert the "fssNS.GenerateFilesRequest" value of type "fssNS.GenerateFilesRequest" to type "fssNS.GenerateFilesRequest"." At C:\SolutionPath\GENERATE_FILES.ps1:23 char:2
+ $response = $srv.GenerateFiles($req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
Generating files for Id 2
Cannot convert argument "req", with value: "fssNS.GenerateFilesRequest", for "GenerateFiles" to type "fssNS.GenerateFilesRequest": "Cannot convert the "fssNS.GenerateFilesRequest" value of type "fssNS.GenerateFilesRequest" to type "fssNS.GenerateFilesRequest"." At C:\SolutionPath\GENERATE_FILES.ps1:23 char:2
+ $response = $srv.GenerateFiles($req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
**Generating files for Id 3**
Generating files for Id 4
Cannot convert argument "req", with value: "fssNS.GenerateFilesRequest", for "GenerateFiles" to type "fssNS.GenerateFilesRequest": "Cannot convert the "fssNS.GenerateFilesRequest" value of type "fssNS.GenerateFilesRequest" to type "fssNS.GenerateFilesRequest"." At C:\SolutionPath\GENERATE_FILES.ps1:23 char:2
+ $response = $srv.GenerateFiles($req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument Generating files for Id 8 Cannot convert argument "req", with value: "fssNS.GenerateFilesRequest", for "GenerateFiles" to type "fssNS.GenerateFilesRequest": "Cannot convert the "fssNS.GenerateFilesRequest" value of type "fssNS.GenerateFilesRequest" to type "fssNS.GenerateFilesRequest"." At C:\SolutionPath\GENERATE_FILES.ps1:23 char:2
+ $response = $srv.GenerateFiles($req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
**Generating files for Id 9**
**Generating files for Id 10**
**Generating files for Id 11**
Generating files for Id 12
Cannot convert argument "req", with value: "fssNS.GenerateFilesRequest", for "GenerateFiles" to type "fssNS.GenerateFilesRequest": "Cannot convert the "fssNS.GenerateFilesRequest" value of type "fssNS.GenerateFilesRequest" to type "fssNS.GenerateFilesRequest"." At C:\SolutionPath\GENERATE_FILES.ps1:23 char:2
+ $response = $srv.GenerateFiles($req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
Sometimes, most calls pass, and only the odd-one fails.
Here's another version of the script, which uses the auto-generated namespaces from New-WebServiceProxy:
$sqlServer=$args[0]
function CallFSS($Id) {
$uri = "http://localhost:1234/FileSystemService.svc?wsdl"
$srv = New-WebServiceProxy -Uri $uri
$type = $srv.GetType().Namespace
$datatype = ($type + '.GenerateFilesRequest')
$req = New-Object($datatype)
$req.Id = $Id
$response = $srv.GenerateFiles($req)
}
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=" + $sqlServer + ";Database=MyDatabase;Integrated Security=True"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "select Id FROM MyTable WHERE Status = 2"
$SqlCmd.Connection = $SqlConnection
$sqlResult = $SqlCmd.ExecuteReader()
while ($sqlResult.Read()) {
$Id = $sqlResult.GetInt32(0)
Write-Host Generating files for Id $Id
CallFSS $Id
}
$SqlCmd.Dispose()
$SqlConnection.Dispose()
$SqlConnection.Close()
Again, the results are inconsistent, though the error I get now relates to the auto-generated namespace:
**Generating files for Id 1**
**Generating files for Id 2**
Generating files for Id 3
Cannot convert argument "req", with value: "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy3234_FileSystemService_svc_wsdl.GenerateFilesRequest", for "GenerateFiles" to type "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy3234_FileSystemService_svc_wsdl.GenerateFilesRequest": "Cannot convert the "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy3234_FileSystemService_svc_wsdl.GenerateFilesRequest" value of type "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy3234_FileSystemService_svc_wsdl.GenerateFilesRequest" to type "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy3234_FileSystemService_svc_wsdl.GenerateFilesRequest"." At C:\SolutionPath\GENERATE_FILES.ps1:23 char:2
+ $response = $srv.GenerateFiles($req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
Generating files for Id 4
Cannot convert argument "req", with value: "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy3234_FileSystemService_svc_wsdl.GenerateFilesRequest", for "GenerateFiles" to type "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy3234_FileSystemService_svc_wsdl.GenerateFilesRequest": "Cannot convert the "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy3234_FileSystemService_svc_wsdl.GenerateFilesRequest" value of type "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy3234_FileSystemService_svc_wsdl.GenerateFilesRequest" to type "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy3234_FileSystemService_svc_wsdl.GenerateFilesRequest"." At C:\SolutionPath\GENERATE_FILES.ps1:23 char:2
+ $response = $srv.GenerateFiles($req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
Etc... execution is different every time.
I dearly hope this is something I'm doing wrong / misunderstanding as I am about to entirely give up on PowerShell. Is this maybe a caching issue? Any help would be greatly appreciated.
Ok, I found something :)
I added an output for the GenerateFiles method definition within the CallFSS function:
$srv | gm -Name GenerateFiles | select -ExpandProperty Definition
Foreach successful request, the output was
void GenerateFiles(fssNS.GenerateFilesRequest req)
The definition was different if I encountered an error:
void GenerateFiles(fssNS.GenerateFilesRequest, oehlvn0y,
Version=0.0.0.0, Culture=neutral, PublicKeyToken=null req)
So if you create the object using the full qualified name, it should work:
function CallFSS($Id)
{
$uri = "http://localhost:11662/Service1.svc?wsdl"
$srv = New-WebServiceProxy -Uri $uri -Namespace fssNS -Class fssClass
# Get the definition of the GenerateFiles method
$definition = $srv | gm -Name GenerateFiles | select -ExpandProperty Definition
# Extract the full qualified type name of the first parameter
$paramType = [regex]::Match($definition, 'GenerateFiles\((.*)\s\w+').Groups[1].Value
$bar = new-object $paramType
$bar.Id = $Id
$response = $srv.GenerateFiles($bar)
}
Note: This solution only works for methods with one parameter due to the regex. However, here is an implementation I would recommend:
function Invoke-FSS # Invoke is a valid Verb (see Get-Verb)
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)]
[int]$Id
)
Begin
{
$uri = "http://localhost:11662/Service1.svc?wsdl"
$srv = New-WebServiceProxy -Uri $uri -Namespace fssNS -Class fssClass
# Get the definition of the GenerateFiles method
$definition = $srv | gm -Name GenerateFiles | select -ExpandProperty Definition
# Extract the full qualified type name of the first parameter
$paramType = [regex]::Match($definition, 'GenerateFiles\((.*)\s\w+').Groups[1].Value
}
Process
{
$bar = new-object $paramType
$bar.Id = $Id
$response = $srv.GenerateFiles($bar)
}
End
{
$srv.Dispose()
}
}
In your example, you would invoke the method by piping the ids to the Invoke-FFS method:
$ids = #()
while ($sqlResult.Read()) {
$ids += $sqlResult.GetInt32(0)
}
$ids | Invoke-FSS
The Begin{} block gets called only once (to initialize your proxy) and the Process{} block gets called for each item in $ids. Finally, the End{} block gets called once at the end to dispose the proxy gracefully.

Identify a file or directory on a SSH machine using net.schmizz.sshj.sftp.SFTPClient api.

I want to identify whether a the given path is a valid path for file or directory using net.schmizz.sshj.sftp.SFTPClient api and based on i need to take decision that if it is a valid file path then i need to access its parent directory. my code looks like below>
SSHClient ssh = new SSHClient();
String rsaKey = "e3:27:12:a9:62:9a:46:cc:98:ee:0d:b7:38:72:a0:63";
String host = "10.235.1.154";
String uName = "root";
String pwd = "pspl#123";
String url = "/root/ram2.log/";
String testUrl = host + url;
ssh.addHostKeyVerifier(rsaKey);
List fileItems = new ArrayList();
1.try {
2. ssh.connect(host);
3. ssh.authPassword(uName,pwd);
4. SFTPClient sftp = ssh.newSFTPClient();
5.
6. if(testUrl.startsWith(host)){
7. String[] splitedStrings = testUrl.split(host);
8. String str = splitedStrings[1];
9. url = str;
10. }else{
11. url = url;
12. }
13.
14.
15. List<RemoteResourceInfo> fileInfoList = sftp.ls(url, new RemoteResourceFilter() {
16. public boolean accept(RemoteResourceInfo rrInfo) {
17. return rrInfo.getName().charAt(0) != '.';
18. }
19. });
20.
21.
22. for (RemoteResourceInfo fileInfo : fileInfoList) {
23. //files.add(str + "/" + fileInfo.getName());
24. String fileName = fileInfo.getName();
25. if (fileInfo.isDirectory()) {
FileItem childFileItem = new FileItem();
childFileItem.setPath(host + url + fileName);
fileItems.add(childFileItem);
} else {
int dotIndex = fileName.lastIndexOf('.');
String ext = dotIndex > 0 ? fileName
.substring(dotIndex + 1) : "";
FileItem childFileItem = new FileItem();
childFileItem.setPath(host + url + fileName);
childFileItem.setDirectory(false);
fileItems.add(childFileItem);
}
}
} catch (IOException e) {
System.out.println("Couldn't resolve host : {} "+ host);
}
return fileItems;
Problem: Line no. 15 is throwing error saying no such file if I m giving the path as "/root/ram2.log/" even though the file ram2.log does exis on server.
Any help on this wud be graet helpful.
You can use lstat to get information about file system objects.
FileAttributes attributes = sftp.lstat(url);
if (attributes.getType() == FileMode.Type.DIRECTORY) {
...
}
But i think your actual problem is that something is odd with the directory "/root/ram2.log/". Maybe no permission, maybe it's not visible to you, maybe it contains a file with a name that isn't encoded properly.

How to create a dynamic variable in Powershell, sucha as date/time etc

Hi i am not exactly sure if my wording is right but i need a variable which contains current date/time whenever i write data to log ; how can i do that without initializing everytime.Currently everytime i need a update i use these both statements jointly.Is there an other way of doing this?
$DateTime = get-date | select datetime
Add-Content $LogFile -Value "$DateTime.DateTime: XXXXX"
please do let me know if any questions or clarifications regarding my question.
This script make the real Dynamic variable in Powershell ( Thanks to Lee Holmes and his Windows PowerShell Cookbook The Complete Guide to Scripting Microsoft's Command Shell, 3rd Edition)
##############################################################################
##
## New-DynamicVariable
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Creates a variable that supports scripted actions for its getter and setter
.EXAMPLE
PS > .\New-DynamicVariable GLOBAL:WindowTitle `
-Getter { $host.UI.RawUI.WindowTitle } `
-Setter { $host.UI.RawUI.WindowTitle = $args[0] }
PS > $windowTitle
Administrator: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
PS > $windowTitle = "Test"
PS > $windowTitle
Test
#>
param(
## The name for the dynamic variable
[Parameter(Mandatory = $true)]
$Name,
## The scriptblock to invoke when getting the value of the variable
[Parameter(Mandatory = $true)]
[ScriptBlock] $Getter,
## The scriptblock to invoke when setting the value of the variable
[ScriptBlock] $Setter
)
Set-StrictMode -Version 3
Add-Type #"
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
namespace Lee.Holmes
{
public class DynamicVariable : PSVariable
{
public DynamicVariable(
string name,
ScriptBlock scriptGetter,
ScriptBlock scriptSetter)
: base(name, null, ScopedItemOptions.AllScope)
{
getter = scriptGetter;
setter = scriptSetter;
}
private ScriptBlock getter;
private ScriptBlock setter;
public override object Value
{
get
{
if(getter != null)
{
Collection<PSObject> results = getter.Invoke();
if(results.Count == 1)
{
return results[0];
}
else
{
PSObject[] returnResults =
new PSObject[results.Count];
results.CopyTo(returnResults, 0);
return returnResults;
}
}
else { return null; }
}
set
{
if(setter != null) { setter.Invoke(value); }
}
}
}
}
"#
## If we've already defined the variable, remove it.
if(Test-Path variable:\$name)
{
Remove-Item variable:\$name -Force
}
## Set the new variable, along with its getter and setter.
$executioncontext.SessionState.PSVariable.Set(
(New-Object Lee.Holmes.DynamicVariable $name,$getter,$setter))
There's a Set-StrictMode -Version 3 but you can set it as -Version 2 if you can load framework 4.0 in your powershell V2.0 session as explained Here
The use for the OP is:
New-DynamicVariable -Name GLOBAL:now -Getter { (get-date).datetime }
Here the Lee Holmes's evaluation (where it is clear what is the real flaw) about the method I used in my other answer:
Note
There are innovative solutions on the Internet that use PowerShell's debugging facilities to create a breakpoint that changes a variable's value whenever you attempt to read from it. While unique, this solution causes PowerShell to think that any scripts that rely on the variable are in debugging mode. This, unfortunately, prevents PowerShell from enabling some important performance optimizations in those scripts.
Why not use:
Add-Content $LogFile -Value "$((Get-Date).DateTime): XXXXX"
This gets the current datetime every time. Notice that it's inside $( ) which makes powershell run the expression(get the datetime) before inserting it into the string.
wrap your two commands in function so you will have just one call ?
function add-log{
(param $txt)
$DateTime = get-date | select -expand datetime
Add-Content $LogFile -Value "$DateTime: $txt"
}
Besides these other ways (which frankly I would probably use instead - except the breakpoint approach), you can create a custom object with a ScriptProperty that you can provide the implementation for:
$obj = new-object pscustomobject
$obj | Add-Member ScriptProperty Now -Value { Get-Date }
$obj.now
Using PsBreakPoint:
$act= #'
$global:now = (get-date).datetime
'#
$global:sb = [scriptblock]::Create($act)
$now = Set-PSBreakpoint -Variable now -Mode Read -Action $global:sb
calling $now returns current updated datetime value
One liner:
$now = Set-PSBreakpoint -Variable now -Mode Read -Action { $global:now = (get-date).datetime }

WMIC - how to use Lenovo SetBiosSetting method

I have a prob calling SetBiosSetting method using WMIC (and also C#)
wmic /namespace:\root\wmi path Lenovo_SetBiosSetting call SetBiosSetting "SecurityChip,Active"
wmic /namespace:\root\wmi path Lenovo_SetBiosSetting call SetBiosSetting SecurityChip,Active
wmic /namespace:\root\wmi path Lenovo_SetBiosSetting call SetBiosSetting ("SecurityChip,Active")
that gives "Invalid Number of Parameters." error, but why ?
Lenovo BIOS Deployment Guide: http://download.lenovo.com/ibmdl/pub/pc/pccbbs/thinkcentre_pdf/hrdeploy_en.pdf
Any Idea ?
I cant use VBS or PowerShell ...
Thanks,Martin
Try this in C#:
ManagementScope scope = new ManagementScope(#"\\.\root\wmi");
//
// Make change(s)
//
SelectQuery queryRead = new SelectQuery("SELECT * from Lenovo_SetBiosSetting");
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, queryRead))
{
using (ManagementObjectCollection queryCollection = searcher.Get())
{
foreach (ManagementObject queryItem in queryCollection)
{
ManagementBaseObject inParams = queryItem.GetMethodParameters("SetBiosSetting");
inParams["parameter"] = "WakeOnLAN,Disable";
ManagementBaseObject outParams = queryItem.InvokeMethod("SetBiosSetting", inParams, null);
string result = outParams["return"] as string; // "Success"
}
}
}
//
// Commit to BIOS
//
queryRead = new SelectQuery("SELECT * from Lenovo_SaveBiosSettings");
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, queryRead))
{
using (ManagementObjectCollection queryCollection = searcher.Get())
{
foreach (ManagementObject queryItem in queryCollection)
{
ManagementBaseObject inParams = queryItem.GetMethodParameters("SaveBiosSettings");
inParams["parameter"] = "";
ManagementBaseObject outParams = queryItem.InvokeMethod("SaveBiosSettings", inParams, null);
string result = outParams["return"] as string; // "Success"
}
}
}
The PowerShell for this is:
(gwmi -class Lenovo_SetBiosSetting -namespace root\wmi).SetBiosSetting("WakeOnLAN,Disable")
I arrived at this post trying to find a way to use WMIC to get all the objects in the Lenovo_BiosSetting class. Your syntax got me on the right track. I had to change your WMIC query to this:
wmic /namespace:\\root\wmi path Lenovo_BiosSetting get
(Note the double back slash)