不得不用实际代码重写这篇文章,因为二进制模块肯定存在某种差异。
完整的cmdlet如下(道歉长度):
简而言之,此函数基本上使用SMO库并从SQL Server实例中提取有关数据库用户的信息。
namespace Namespace
{
using Microsoft.SqlServer.Management.Smo;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using static PrivateFunctions;
[Cmdlet(VerbsCommon.Get, "DatabaseUserInformation")]
public class GetDatabaseUserInformationCmdlet : PSCmdlet
{
[Parameter(Mandatory = true,
HelpMessage = "The user name of the account to retrieve information for.",
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
public string LogonName { get; set; }
private List<object> userInformation = new List<object>();
protected override void ProcessRecord()
{
string samAccountName = GetSamAccountName(LogonName);
Login login = null;
User user = null;
WriteVerbose($"Getting login for account: {samAccountName}...");
try
{
login = GetLogin(samAccountName);
}
catch (InvalidOperationException invalidOperation)
{
ThrowTerminatingError(new ErrorRecord(
invalidOperation,
"LoginNotFound",
ErrorCategory.InvalidOperation,
login));
}
WriteVerbose($"Getting user for login: {login.Name}...");
try
{
user = GetUser(login);
}
catch (InvalidOperationException invalidOperation)
{
ThrowTerminatingError(new ErrorRecord(
invalidOperation,
"UserNotFound",
ErrorCategory.InvalidOperation,
user));
}
WriteVerbose($"Gathering information for user: {user.Name}");
var information = new
{
LoginName = login.Name,
UserName = user.Name,
FullAccess = TestFullAccessOnDatabase(user),
Roles = user.EnumRoles()
};
userInformation.Add(information);
}
protected override void EndProcessing()
{
WriteVerbose("Writing information to output.");
userInformation.ForEach(item => WriteObject(item));
}
}
}
cmdlet可以与单个参数一起使用:
Get-DatabaseUserInformation user1
或者我也想在处理多个用户时能够将数组管道化。
@('user1', 'user2','user3') | Get-DatabaseUserInformation
如果我使用的是单个值并且该用户不存在,那么公平,它会终止,并且需要更正并重新运行它。
但是当我将它与多个值一起使用时,如果其中一个值不存在,它就不会提供任何输出,只有例外。
所以当一切正常时我得到的输出是这样的(详细说明):
VERBOSE: Getting login for account: DOMAIN\user1...
VERBOSE: Getting user for login: DOMAIN\user1...
VERBOSE: Gathering information for user: dbo
VERBOSE: Getting login for account: DOMAIN\user2...
VERBOSE: Getting user for login: DOMAIN\user2...
VERBOSE: Gathering information for user: user2
VERBOSE: Getting login for account: DOMAIN\user3...
VERBOSE: Getting user for login: DOMAIN\user3...
VERBOSE: Gathering information for user: user3
VERBOSE: Writing information to output.
LoginName UserName FullAccess Roles
--------- -------- ---------- -----
DOMAIN\user1 dbo True {db_owner}
DOMAIN\user2 user2 False {role1}
DOMAIN\user3 user3 False {}
当出现问题时我得到的结果:(在这种情况下,user2拼错了。)
Get-DatabaseUserInformation : A login for the account 'DOMAIN\usr2' does not
exist in the database.
At line:1 char:6
+ $x | Get-DatabaseUserInformation -verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-DatabaseUserInformation], InvalidOperationException
+ FullyQualifiedErrorId : LoginNotFound,DatabaseUserManagement.GetDatabase
UserInformationCmdlet
我想要发生的事情与此类似。
VERBOSE: Getting login for account: DOMAIN\user1...
VERBOSE: Getting user for login: DOMAIN\user1...
VERBOSE: Gathering information for user: dbo
VERBOSE: Getting login for account: DOMAIN\usr2...
Get-DatabaseUserInformation : A login for the account 'DOMAIN\usr2' does not
exist in the database.
At line:1 char:6
+ $x | Get-DatabaseUserInformation -verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-DatabaseUserInformation], InvalidOperationException
+ FullyQualifiedErrorId : LoginNotFound,DatabaseUserManagement.GetDatabase
UserInformationCmdlet
VERBOSE: Getting login for account: DOMAIN\user3...
VERBOSE: Getting user for login: DOMAIN\user3...
VERBOSE: Gathering information for user: user3
VERBOSE: Writing information to output.
LoginName UserName FullAccess Roles
--------- -------- ---------- -----
DOMAIN\user1 dbo True {db_owner}
DOMAIN\user3 user3 False {}
答案 0 :(得分:3)
编辑:问题显然在ThrowTerminating错误中。在这里阅读msdn描述:
备注部分声明如果要继续处理管道,则不应使用此方法:
当cmdlet遇到终止错误时,请调用此方法 而不仅仅是抛出一个例外。调用此方法允许 用于附加描述的其他错误记录信息的cmdlet 导致终止错误的条件。当这个方法是 调用,Windows PowerShell运行时捕获错误记录和 然后开始关闭管道。有关的更多信息 错误报告和错误记录,请参阅Windows PowerShell错误 报告。当错误发生时,不应使用此方法 cmdlet可以继续处理记录。发送错误报告时 发生非终止错误,调用WriteError方法。更多 有关cmdlet的信息,请参阅Windows PowerShell Cmdlet。
你必须写一个像这样的高级函数:
Function Get-StringLength()
{
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline=$true)]
$value
)
Begin {}
Process {
Write-Output $value.Length
}
End {}
}
Begin块是您准备某些东西的地方,Process块是您从管道处理每个对象的地方,这意味着它是为管道中的每个对象运行的。你清理End块中的混乱。
因为它是一个cmdlet,所以你可以使用ErrorAction来控制错误发生的事情:
$values | Get-StringLength -ErrorAction SilentlyContinue
您甚至可以使用以下方法将这些错误放入变量中:
$values | Get-StringLength -ErrorAction SilentlyContinue -ErrorVariable MyErrors
答案 1 :(得分:1)
也许抛出一个try / catch语句,通常对我有用。否则,我会查看这两个主题:
答案 2 :(得分:1)
借用早期版本中的代码我创建了一个接受管道输入的简单函数。对于传递的每个对象,我们尝试从Active Directory获取用户。在内部cmdlet上设置-ErrorAction
时,我感到很惊讶。所以简单的解决方案是设置一个try / catch块而不是catch动作。
Function Get-AdUsers()
{
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline=$true)]
$value
)
Process {
try{Get-ADUser $value}catch{}
}
}
$values = 'gooduser1','badname','gooduser2'
$values | Get-AdUsers
所以上面返回2个用户对象。如果我删除try
块我仍然得到相同的两个对象,但我也得到一个错误。使用try
抑制它。
在您的更新代码中,您将收到终止错误,因为这是您定义它的方式。尝试将catch块留空,看看是否有效。
答案 3 :(得分:0)
您需要编写过滤功能,而不是常规功能。为此,将函数体放在process
块中:
function Get-StringLength()
{
[CmdletBinding()]
Param
(
[Parameter(ValueFromPipeline=$true)]
$value
)
process
{
Write-Output $value.Length
}
}
这将导致为管道中的每个项调用一次过滤器。