SQL Server stored procedure from Powershell failing to execute, it has both input and output values

My PowerShell is attempting to execute a stored procedure, passing in two input variables and expecting an output value. This code is based on another question here, but I can't get an output value, which the original question didn't ask.

Code update: I actually managed to pull this off using:

$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = $SQLConnectionString
$SQLConnection.Open()

$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "proc_InsertOrganizationSecret"
$SqlCmd.Connection = $SqlConnection
$SqlCmd.CommandType = [System.Data.CommandType]'StoredProcedure';

$param1=$sqlcmd.Parameters.Add("@OrganizationId", [System.Data.SqlDbType]::Int)
$param1.Value=10

$param1=$sqlcmd.Parameters.Add("@Secret", [System.Data.SqlDbType]::NVarChar)
$param1.Value="HelloWorld"

$paramReturn = $sqlCmd.Parameters.Add("@ReturnValue", [System.Data.SqlDbType]::Int)
$paramReturn.Direction = [System.Data.ParameterDirection]::ReturnValue

$result = $SqlCmd.ExecuteNonQuery()

$returnValue = [int]$sqlCmd.Parameters["@ReturnValue"].Value

Write-Host Return value is $returnValue

$SQLConnection.Close()

When I try to call ExecuteNonQuery(), I get this error:

Exception calling "ExecuteNonQuery" with "0" argument(s): "Procedure or function proc_InsertOrganizationSecret has too many arguments specified.

At P:\Orasi\Code\terumo_bct\MainGithubScript.ps1:149 char:1

  • $result = $SqlCmd.ExecuteNonQuery();
  • CategoryInfo : NotSpecified: (:) [], MethodInvocationException
  • FullyQualifiedErrorId : SqlException

Here is the PowerShell:

$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = $SQLConnectionString
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "proc_InsertOrganizationSecret"
$SqlCmd.Connection = $SqlConnection
$SqlCmd.CommandType = [System.Data.CommandType]'StoredProcedure';

$outParameter = new-object System.Data.SqlClient.SqlParameter;
$outParameter.ParameterName = "@SecretId";
$outParameter.Direction = [System.Data.ParameterDirection]'Output';
$outParameter.DbType = [System.Data.DbType]'int32';
$outParameter.Size = 2500;
$outParameter.Direction = [System.Data.ParameterDirection]'Input';

$inParameter = new-object System.Data.SqlClient.SqlParameter;
$inParameter.ParameterName = "@OrganizationId"
$inParameter.Value="10"
$inParameter.DbType = [System.Data.DbType]'int32';
$inParameter.Size = 2500;

$in2Parameter = new-object System.Data.SqlClient.SqlParameter;
$in2Parameter.ParameterName = "@Secret"
$in2Parameter.Value="HelloWorld"
$in2Parameter.DbType = [System.Data.DbType]'string';
$in2Parameter.Size = 2500;

$inParameter.Direction=[System.Data.ParameterDirection]'Input';
$in2Parameter.Direction=[System.Data.ParameterDirection]'Input';

$SqlCmd.Parameters.Add($outParameter) >> $null;
$SqlCmd.Parameters.Add($inParameter) >> $null;
$SqlCmd.Parameters.Add($in2Parameter) >> $null;

$SqlConnection.Open();

$result = $SqlCmd.ExecuteNonQuery();
$truth = $SqlCmd.Parameters["@SecretId"].Value;
$SqlConnection.Close();
$truth;

And here is the stored procedure:

CREATE OR ALTER PROCEDURE [dbo].[proc_InsertOrganizationSecret] 
    @OrganizationId int, 
    @Secret nvarchar(255)
AS
BEGIN
    -- Suppress query output
    SET NOCOUNT ON;

    DECLARE @SecretId int

    INSERT INTO dbo.OrganizationSecrets (OrganizationId, Secret) 
    VALUES (@OrganizationId, @Secret)

    SET @SecretId = SCOPE_IDENTITY()

    RETURN @SecretId
END

@SecretId is not an output parameter, although it should be. Currently its a ReturnValue, so [System.Data.ParameterDirection]::ReturnValue

But it's against TSQL coding conventions and best practices to return data through a stored procedure return value; it's a mostly-obsolete mechanism to signal success or failure of the procedure.

So the proc should be returned through an output parameter:

PROCEDURE [dbo].[proc_InsertOrganizationSecret] 
    @OrganizationId int, @Secret nvarchar(255), @SecretId int output
AS
BEGIN
    -- Supress query output
    SET NOCOUNT ON;

    DECLARE @SecretId int

    INSERT INTO dbo.OrganizationSecrets (OrganizationId, Secret) VALUES (@OrganizationId, @Secret)

    SET @SecretId=SCOPE_IDENTITY()


END

or a resultset

PROCEDURE [dbo].[proc_InsertOrganizationSecret] 
    @OrganizationId int, @Secret nvarchar(255), @SecretId int output
AS
BEGIN
    -- Supress query output
    SET NOCOUNT ON;

    DECLARE @SecretId int

    INSERT INTO dbo.OrganizationSecrets (OrganizationId, Secret) VALUES (@OrganizationId, @Secret)

    select SCOPE_IDENTITY() SecretId    

END

which you would access with SqlCommand.ExecuteScalar, or .ExecuteReader.